Skip to main content
The SDK supports several advanced use-cases for more customized integration.

Callbacks instead of events

If you prefer not to use event emitters, you can supply callback functions directly in the createCheckout options for success, error, and status changes. This provides a quick way to handle outcomes without separately registering event listeners:
const checkout = await createCheckout({
  priceId: 'price_123',
  customer: {
    externalId: 'user_456',
    email: 'user@example.com',
  },
  container: '#checkout',

  // Callback style (alternative to .on() events)
  onSuccess: result => {
    console.log('Success!', result.orderId);
  },
  onError: error => {
    console.error('Error!', error.message);
  },
  onStatusChange: (newState, oldState) => {
    console.log(`${oldState}${newState}`);
  },
});
Using callbacks is equivalent to listening for the 'success', 'error', and 'status-change' events on the CheckoutInstance. Internally, the SDK will trigger these callbacks at the same time as the events. Choose the approach (callbacks vs. event listeners) that fits your application style; you can even mix them (for example, provide an onSuccess callback but also listen for 'status-change' events).

Manual session creation

For full control over the checkout flow, you can manually create a client session and then use it with Primer’s Headless Checkout. This is useful if you need to perform custom steps between tokenization and finalizing payment (for example, if you want to process the payment on your backend before confirming the UI).

1. Create client session

Create a client session to get a clientToken (and orderId):
import { createClientSession } from '@funnelfox/billing';
import { Primer } from '@primer-io/checkout-web';

const session = await createClientSession({
  priceId: 'price_123',
  externalId: 'user_456',
  email: 'user@example.com',
  orgId: 'your-org-id',
});
console.log('Client token:', session.clientToken);
console.log('Order ID:', session.orderId);

2. Use with Primer Headless Checkout

Use the obtained clientToken with Primer’s Headless Checkout:
const headlessCheckout = await Primer.createHeadless(session.clientToken, {
  paymentHandling: 'MANUAL',
  apiVersion: '2.4',
  onTokenizeSuccess: async (paymentMethodTokenData, handler) => {
    // Your custom payment logic...
    // Call your payment API with paymentMethodTokenData.token
    handler.handleSuccess();
  },
});

await headlessCheckout.start();
In this flow, you manually control when to display the checkout and what happens with the payment data. After calling createClientSession, you initialize Primer’s Headless Checkout with the clientToken. The onTokenizeSuccess callback gives you the opportunity to handle the payment token (paymentMethodTokenData.token) as needed. Once your server confirms the payment or subscription creation, you call handler.handleSuccess() to complete the flow (or call handler.handleFailure() if an error occurred). This advanced approach is useful for integrating additional custom business logic into the payment flow.