Skip to main content
npm install @insforge/sdk@latest
import { createClient } from '@insforge/sdk';

const insforge = createClient({
  baseUrl: 'https://your-app.insforge.app',
  anonKey: 'your-anon-key'  // Optional: for public/unauthenticated requests
});

Overview

The TypeScript SDK exposes Stripe runtime helpers for generated app frontends:
  • insforge.payments.stripe.createCheckoutSession(...)
  • insforge.payments.stripe.createCustomerPortalSession(...)
Stripe secret keys, catalog management, webhook setup, and payment monitoring are admin operations. Configure them from the dashboard or CLI before using the SDK.
npx @insforge/cli payments stripe status
npx @insforge/cli payments stripe catalog --environment test
See Stripe Payments for setup, database tables, webhook projections, and fulfillment patterns.
The SDK methods require the current InsForge user token. Anonymous InsForge tokens can be used for guest one-time checkout, but an InsForge API key is not a substitute because the backend needs user context for local session rows.

createCheckoutSession()

Create a Stripe Checkout Session through the InsForge backend.

Parameters

ParameterTypeRequiredDescription
first argument'test' | 'live'YesStripe environment to target
mode'payment' | 'subscription'YesCheckout mode
lineItems{ priceId: string; quantity?: number }[]YesStripe Price IDs and quantities. Quantity defaults to 1
successUrlstringYesURL Stripe redirects to after Checkout completes
cancelUrlstringYesURL Stripe redirects to if the customer cancels
subject{ type: string; id: string }Required for subscriptionsApp-defined billing owner
customerEmailstring | nullNoEmail hint for Checkout customer creation
metadataRecord<string, string>NoApp metadata copied to Stripe Checkout
idempotencyKeystringNoStable key for retry-safe Checkout creation
Metadata keys starting with insforge_ are reserved.

Returns

{
  data: {
    checkoutSession: {
      id: string
      environment: 'test' | 'live'
      mode: 'payment' | 'subscription'
      status: 'initialized' | 'open' | 'completed' | 'expired' | 'failed'
      paymentStatus: 'paid' | 'unpaid' | 'no_payment_required' | null
      subjectType: string | null
      subjectId: string | null
      customerEmail: string | null
      checkoutSessionId: string | null
      customerId: string | null
      paymentIntentId: string | null
      subscriptionId: string | null
      url: string | null
      lastError: string | null
      createdAt: string
      updatedAt: string
    }
  } | null,
  error: Error | null
}

One-time checkout

const { data, error } = await insforge.payments.stripe.createCheckoutSession('test', {
  mode: 'payment',
  lineItems: [{ priceId: 'price_123', quantity: 1 }],
  successUrl: `${window.location.origin}/checkout/success`,
  cancelUrl: `${window.location.origin}/pricing`,
  customerEmail: user?.email ?? null,
  metadata: { order_id: orderId },
  idempotencyKey: `order:${orderId}`
});

if (error) {
  console.error('Checkout failed:', error.message);
  return;
}

if (data?.checkoutSession.url) {
  window.location.assign(data.checkoutSession.url);
}
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

const { data, error } = await insforge.payments.stripe.createCheckoutSession('test', {
  mode: 'subscription',
  subject: { type: 'team', id: teamId },
  lineItems: [{ priceId: 'price_monthly_123', quantity: 1 }],
  successUrl: `${window.location.origin}/billing/success`,
  cancelUrl: `${window.location.origin}/billing`,
  customerEmail: user.email,
  idempotencyKey: `team:${teamId}:pro-monthly`
});

if (error) throw error;
if (data?.checkoutSession.url) {
  window.location.assign(data.checkoutSession.url);
}
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 verified webhook events to fulfill orders and grant subscription access.

createCustomerPortalSession()

Create a Stripe Billing Portal Session for a mapped billing subject.

Parameters

ParameterTypeRequiredDescription
first argument'test' | 'live'YesStripe environment to target
subject{ type: string; id: string }YesApp-defined billing owner
returnUrlstringNoURL Stripe redirects to when the customer leaves the portal
configurationstringNoStripe Billing Portal configuration ID

Returns

{
  data: {
    customerPortalSession: {
      id: string
      environment: 'test' | 'live'
      status: 'initialized' | 'created' | 'failed'
      subjectType: string
      subjectId: string
      customerId: string | null
      returnUrl: string | null
      configuration: string | null
      url: string | null
      lastError: string | null
      createdAt: string
      updatedAt: string
    }
  } | null,
  error: Error | null
}

Example

const { data, error } = await insforge.payments.stripe.createCustomerPortalSession('test', {
  subject: { type: 'team', id: teamId },
  returnUrl: `${window.location.origin}/billing`
});

if (error) {
  if ('statusCode' in error && error.statusCode === 404) {
    return;
  }

  throw error;
}

if (data?.customerPortalSession.url) {
  window.location.assign(data.customerPortalSession.url);
}
Customer portal sessions require an authenticated user and an existing customer mapping for the subject. The mapping is usually created after a Checkout Session completes and Stripe returns a customer.

Authorization and RLS

The SDK methods call runtime routes using the current InsForge token. The backend inserts local session rows using the caller context:
  • payments.stripe_checkout_sessions for Checkout attempts
  • payments.stripe_customer_portal_sessions for Billing Portal attempts
If users can pass shared subjects such as teams or organizations, add an authorization boundary before exposing checkout, subscription, or customer portal UI. For example, enable RLS on the Stripe runtime tables with policies that check team membership, or call Payments through your own server endpoint that checks membership first. PostgreSQL applies SELECT policies to rows returned by INSERT ... RETURNING and to idempotent retry lookups. If an RLS error appears even though an INSERT policy exists, add a matching SELECT policy for the same billing subject and idempotency key.
Do not let users submit arbitrary subject.type and subject.id values unless your app checks that they can manage that billing subject.

Reading payment state

The Payments SDK does not expose generic end-user reads for payments.customers, payments.stripe_subscriptions, or payments.transactions. Those tables are operational records used for dashboard visibility and reporting. For user-facing billing state, create app-owned tables with RLS and populate them from provider webhook event triggers:
  • public.orders
  • public.credit_ledger
  • public.user_entitlements
  • public.team_billing_status
See Stripe Payments for fulfillment examples.

Live/test environment

Pass 'test' as the first SDK argument 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.