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).

Custom Primer options

Primer’s Universal Checkout supports various configuration options (payment methods, button styles, etc.). You can pass these through the Billing SDK via the universalCheckoutOptions field when creating a checkout. These options will be forwarded to Primer’s SDK. For example, to customize the PayPal button color and payment flow, and apply custom style overrides:
const checkout = await createCheckout({
  priceId: 'price_123',
  customer: {
    externalId: 'user_456',
    email: 'user@example.com',
  },
  container: '#checkout',

  // Pass options to Primer's Universal Checkout
  universalCheckoutOptions: {
    paypal: {
      buttonColor: 'gold',
      paymentFlow: 'PREFER_VAULT',
    },
    style: {
      // Custom styling options...
    },
  },
});
In the above snippet, we set the PayPal button color to gold and use a specific payment flow. You can similarly configure other payment methods and UI aspects. Learn more about all available universalCheckoutOptions in Primer’s documentation.

Manual session creation

For full control over the checkout flow, you can manually create a client session and then launch the Primer 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, showUniversalCheckout } from '@funnelfox/billing';

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. Show Primer checkout

Use the obtained clientToken to show the Primer checkout UI:
const primerCheckout = await showUniversalCheckout(session.clientToken, {
  container: '#checkout',
  onTokenizeSuccess: async (data, handler) => {
    // Your custom payment logic here (e.g., send `data` to your server)
    // ...
    // After processing payment on server:
    handler.handleSuccess();  // or handler.handleFailure() if an error occurred
  },
});
In this flow, you manually control when to display the checkout and what happens with the payment data. After calling createClientSession, you might send the clientToken to your frontend (or generate it on the frontend as shown above). Then, showUniversalCheckout renders the payment form. The onTokenizeSuccess callback gives you the opportunity to handle the payment token (data) as needed. Once your server confirms the payment or subscription creation, you call handler.handleSuccess() to let the Primer UI know it can show a success state (or call handler.handleFailure() to show an error state). This advanced approach is useful for integrating additional custom business logic into the payment flow.
I