Payments & credits
Checkout, Stripe, Creem, webhooks, and user credits.
Overview
Checkout is initiated from POST /api/checkout: validates product_id against the pricing page from getPricingPage(locale), then creates an order via insertOrder and either Stripe Checkout or Creem depending on integration config (src/integrations/stripe, src/integrations/creem).
Webhooks & callbacks
| Path | Purpose |
|---|---|
/api/pay/callback/stripe, /api/pay/notify/stripe | Stripe return + webhook style handling |
/api/pay/callback/creem, /api/pay/notify/creem | Creem equivalents |
Handlers update order status and apply credits through src/models/order.ts, src/models/credit.ts, and src/services/order.ts / credit.ts (idempotent patterns recommended for webhooks).
Credits API
/api/get-user-credits— exposes remaining credits for the logged-in user (used by console/billing UI).
Data flow
- Client posts
product_id(+currency,locale). - Checkout route resolves pricing item → builds order row → returns payment provider session/url.
- Provider calls back → notify routes verify signature → credits updated → UI refreshes via session or client fetch.
Key files
src/app/api/checkout/route.tssrc/integrations/stripe/index.ts,src/integrations/creemusagesrc/services/order.ts,src/services/credit.ts
Dependencies
Environment
PAY_PROVIDER—"stripe"or Creem (seecheckout/route.ts).NEXT_PUBLIC_WEB_URL,NEXT_PUBLIC_PROJECT_NAME,NEXT_PUBLIC_PAY_CANCEL_URL— Stripe/Creem return URLs and branding.- Stripe:
STRIPE_PRIVATE_KEY,STRIPE_WEBHOOK_SECRET. - Creem:
CREEM_API_KEY,CREEM_ENV,CREEM_PRODUCTS(JSON product map),CREEM_WEBHOOK_SECRET(/api/pay/notify/creem).
Database (src/db/schema.ts)
orders,credits,affiliates
Unconfigured gateways
Checkout returns HTTP 503 with a user-facing availability message when the selected
PAY_PROVIDER has no API key (or is unsupported). No order is inserted in this case.
Automated gateway tests use a mocked Stripe client; they do not prove live payment settlement.