Stripe secret keys, catalog management, sync, webhook setup, and payment monitoring in the InsForge dashboard are admin operations. Configure them from the dashboard or CLI before using the SDK.
npx @insforge/cli payments statusnpx @insforge/cli payments catalog --environment test
See Payments Architecture for setup, Stripe key management, webhook projections, and fulfillment patterns.
For anonymous one-time purchases, omit subject and pass customerEmail when available.If one-time checkout includes a subject and there is no existing Stripe customer mapping yet, InsForge lets Stripe create the customer during Checkout and backfills the subject mapping from the completion webhook.
Subscription checkout requires subject because recurring access belongs to an app-defined billing owner, such as a user, team, organization, workspace, tenant, or group.
Do not treat the success URL as proof of payment. Use webhook-projected payment state to fulfill orders and grant subscription access.
const { data, error } = await insforge.payments.createCustomerPortalSession({ environment: 'test', subject: { type: 'team', id: teamId }, returnUrl: `${window.location.origin}/billing`});if (error) { if ('statusCode' in error && error.statusCode === 404) { // No Stripe customer mapping exists yet. Show a subscribe CTA instead. return; } throw error;}if (data?.customerPortalSession.url) { window.location.assign(data.customerPortalSession.url);}
Customer portal sessions require an authenticated user and an existing Stripe customer mapping for the subject. The mapping is usually created after a Checkout Session completes and Stripe returns a customer. The synced customer data shown in the Payments dashboard can help you verify what happened, but portal creation relies on payments.stripe_customer_mappings.
The SDK methods call runtime routes using the current InsForge token. The backend inserts local session rows using the caller context:
payments.checkout_sessions for Checkout attempts
payments.customer_portal_sessions for Billing Portal attempts
In practice, one-time checkout can support guest or signed-in flows, while customer portal creation requires an authenticated user because it operates on an existing billing subject mapping.If users can pass shared subjects such as teams or organizations, enable app-specific RLS policies before exposing subscription checkout or customer portal UI. For example, if subscriptions belong to teams, only team members should be able to create sessions for that team.
Do not let users submit arbitrary subject.type and subject.id values unless your app has matching RLS policies.
The Payments SDK does not expose generic end-user reads for payments.customers, payments.subscriptions, or payments.payment_history. Those tables are operational records used for dashboard visibility and fulfillment workflows.Refunds, disputes, and other sensitive financial operations should still be handled in the Stripe Dashboard.For user-facing billing state, create app-owned tables with RLS and populate them from payment projection triggers:
public.orders
public.credit_ledger
public.user_entitlements
public.team_billing_status
Populate those tables from webhook-projected payment state. See Payments Architecture for examples.
Do not mark an order paid, grant credits, or activate a subscription from the success URL alone. Stripe recommends webhooks for reliable fulfillment because customers might complete payment without returning to your app.
Then add a database trigger that listens to payments.payment_history and updates public.orders when the matching row becomes type = 'one_time_payment' and status = 'succeeded'. The success page can read the order and show pending, paid, or fulfilled.
Use environment: 'test' while developing. Only switch to live after the developer explicitly approves production Stripe changes and live prices are configured.
Never put Stripe secret keys in frontend code or public deployment environment variables. Configure Stripe keys through the InsForge dashboard or CLI.