Payments Overview
Choose one active payment provider and understand the provider-neutral checkout contract.
VibeAny supports Stripe and Creem behind one application-level payment contract. A deployment uses exactly one active provider for new checkout and webhook traffic.
Enable payments
Two settings control the feature:
NEXT_PUBLIC_ENABLE_PAYMENTS=true
PAYMENTS_PROVIDER=stripe # or creemThere is no automatic fallback between payment providers. When payments are enabled, npm run preflight verifies the selected provider's credentials, webhook signing secret, product catalog, and subscription credit scheduler configuration.
What the provider switch controls
| Operation | Provider selection |
|---|---|
| New subscription checkout | Current PAYMENTS_PROVIDER |
| New credit-pack or one-time checkout | Current PAYMENTS_PROVIDER |
| Incoming webhook verification | Current PAYMENTS_PROVIDER |
| Cancel an existing subscription | Provider stored on that subscription |
| Open an existing subscription's billing portal | Provider stored on that subscription |
Changing
PAYMENTS_PROVIDERis not a subscription migration. The starter does not migrate customers, payment methods, subscriptions, or old-provider webhook ownership. Do not switch a live deployment with active subscriptions without a separate migration and backfill plan.
The inactive provider receives no new checkout traffic and is not a fallback for the active webhook route. However, old-provider credentials and API access must remain available while subscriptions stored with that provider still need portal or cancellation operations. Retire those credentials only after the old subscription population has been migrated or closed and its remaining webhook obligations have been handled.
Unified API
The browser and application use provider-neutral routes:
| Method | Route | Purpose |
|---|---|---|
POST | /api/payments/checkout | Create a credit-pack or supported one-time checkout from { skuKey } |
POST | /api/payments/subscription/checkout | Create a subscription checkout from { planKey, period } |
GET | /api/payments/subscription | Read the signed-in user's subscription |
POST | /api/payments/portal | Open the stored provider's customer portal |
POST | /api/payments/subscription/cancel | Schedule cancellation at period end |
POST | /api/payments/webhook | Verify and process the active provider's webhook |
POST | /api/payments/confirm | Acknowledge signed Creem return parameters; fulfillment remains deferred to webhook |
Checkout routes require an authenticated user with an email address. A user can have only one effective subscription. Active, trialing, past-due, unpaid, paused, and scheduled-for-cancellation subscriptions all block a second subscription checkout.
Catalog source of truth
Plans, credit packages, display prices, credit grants, and provider identifiers are defined in src/lib/config/products.ts.
The built-in visible catalog contains:
- Starter and Pro subscriptions, each with monthly and annual billing;
- Small, Medium, and Large one-time credit packs;
- example landing products that require custom fulfillment work before they can be sold.
The setup wizard asks for all four subscription identifiers and all three credit-pack identifiers for the selected provider. If you remove a visible SKU, update the UI, catalog, readiness checks, and tests together.
Payment completion is asynchronous
A hosted checkout redirect only proves that the customer returned to your site. It does not prove that payment was verified or fulfillment succeeded.
Treat these as the acceptance boundary:
- the provider sends a signed webhook;
- the webhook is processed without error or is safely deduplicated;
- the expected subscription or credit transaction is visible in the database;
- replaying the webhook does not apply fulfillment twice.
Creem return signatures are acknowledged by /api/payments/confirm, but the handler deliberately returns a deferred result. Stripe's normal return is a generic success message. Both providers rely on webhook processing for durable state.
Refund policy boundary
VibeAny can evaluate a configurable subscription-usage threshold, but it does not call a provider refund API. Approved refunds are issued manually in the dashboard of the provider that processed the original charge. Refunds do not automatically cancel subscriptions or reverse credit lots.
See Webhooks, subscriptions, and credits for fulfillment, monthly grants, and the manual refund workflow. Continue with Stripe setup or Creem setup for provider-specific configuration.