Stripe
A full-stack library for Stripe subscriptions.
Solving split brain integrations with a full-stack library.
Install
npm install @fragno-dev/stripe @fragno-dev/dbMount route
/api/stripe
Includes
Webhooks + state
Best for
Subscriptions
Flow
A billing event should move cleanly through your stack.
Billing flow
- 1
Checkout session
Stripe creates a session and redirects the customer.
- 2
Webhook event
The fragment syncs subscription state into your database.
- 3
In-app hooks
Use typed hooks to trigger upgrades, cancellations, or portals.
Capabilities
The common billing seams are already packaged.
Checkout + billing portal
Create subscriptions, upgrades, and cancellations directly from your frontend.
Automatic webhook sync
Keep subscription state up to date with Stripe events and sync helpers.
Database-backed state
The fragment stores subscription data in your own database.
Blueprint
Configure the server once, then expose typed billing actions.
1. Install
Install the fragment and the Fragno DB package.
npm install @fragno-dev/stripe @fragno-dev/db2. Create the fragment server
Configure Stripe secrets and map customers to your users.
import { createStripeFragment } from "@fragno-dev/stripe";import { getSession } from "@/lib/auth";import { updateEntity } from "@/db/repo";export const stripeFragment = createStripeFragment({ stripeSecretKey: process.env.STRIPE_SECRET_KEY!, webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!, onStripeCustomerCreated: async (stripeCustomerId, referenceId) => { await updateEntity(referenceId, { stripeCustomerId }); }, resolveEntityFromRequest: async (context) => { const session = getSession(context.headers); return { referenceId: session.user.id, customerEmail: session.user.email, stripeCustomerId: session.user.stripeCustomerId || undefined, stripeMetadata: {}, }; },});3. Mount routes + generate schema
Expose the Stripe handlers and generate schema migrations.
import { stripeFragment } from "@/lib/stripe";export const handlers = stripeFragment.handlersFor("react-router");export const action = handlers.action;export const loader = handlers.loader;// Generate schema// npx fragno-cli db generate lib/stripe.ts --format drizzle -o db/stripe.schema.ts4. Create a client
Generate typed hooks for billing flows.
import { createStripeFragmentClient } from "@fragno-dev/stripe/react";export const stripeClient = createStripeFragmentClient();Use it
Billing logic stays typed on both sides of the boundary.
Frontend action
import { stripeClient } from "@/lib/stripe-client";export function SubscribeButton() { const { mutate, loading } = stripeClient.upgradeSubscription(); const handleSubscribe = async () => { const { url, redirect } = await mutate({ body: { priceId: "price_123", successUrl: `${window.location.origin}/success`, cancelUrl: window.location.href, }, }); if (redirect) { window.location.href = url; } }; return ( <button onClick={handleSubscribe} disabled={loading}> {loading ? "Loading..." : "Subscribe"} </button> );}Server services
import { stripeFragment } from "@/lib/stripe";const subscriptions = await stripeFragment.services.getSubscriptionsByReferenceId(user.id);const subscription = await stripeFragment.services.getSubscriptionById(subscriptionId);const byCustomer = await stripeFragment.services.getSubscriptionsByStripeCustomerId(customerId);