> ## Documentation Index
> Fetch the complete documentation index at: https://docs.numeral.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Numeral for Stripe Checkout

> Calculate tax, validate customer location, and create Stripe Checkout Sessions with one Numeral API call.

Numeral for Stripe Checkout is a server-side replacement for creating a Stripe Checkout Session directly. Send Numeral the same Stripe Price IDs and checkout URLs you already use. Numeral determines the customer's tax location, calculates tax, prepares Stripe Checkout, and returns the next URL for the buyer.

<CardGroup cols={2}>
  <Card title="Keep Stripe Checkout" icon="stripe">
    Stripe still collects payment details and completes the payment. Numeral prepares the cart with the correct tax first.
  </Card>

  <Card title="Use the best location signal" icon="location-dot">
    Send a complete address, a customer IP address, or let Numeral collect only the missing location fields.
  </Card>

  <Card title="Choose the buyer experience" icon="window-maximize">
    Redirect through a Numeral-hosted address step or embed the secure collector directly in your checkout.
  </Card>

  <Card title="Validate before payment" icon="circle-check">
    Numeral checks location data before tax is finalized, including mismatched state or province and postal code combinations.
  </Card>
</CardGroup>

## A small change to your Stripe integration

Instead of calling `stripe.checkout.sessions.create(...)`, call `numeral.tax.bridge.sessions.create(...)`. The checkout object remains familiar: it uses your connected Stripe account, Stripe Price IDs, line-item quantities, and success and cancel URLs.

<CodeGroup>
  ```ts Stripe theme={null}
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    line_items: [{ price: "price_123", quantity: 1 }],
    success_url: "https://store.example/success",
    cancel_url: "https://store.example/cart",
  });
  ```

  ```ts Numeral theme={null}
  const session = await numeral.tax.bridge.sessions.create({
    config_id: "brcfg_123",
    collection_mode: "hosted",
    confirmation_method: "automatic",
    checkout: {
      mode: "payment",
      line_items: [{ price: "price_123", quantity: 1 }],
      success_url: "https://store.example/success",
      cancel_url: "https://store.example/cart",
    },
    tax_context: {
      location: {
        basis: "billing_address",
        address: { country: "US" },
      },
    },
    "X-API-Version": "2026-03-01",
    "Idempotency-Key": crypto.randomUUID(),
  });
  ```
</CodeGroup>

<Note>
  The initial release supports one-time Stripe Checkout payments. Subscription mode is not part of the public launch contract.
</Note>

## How it works

```mermaid theme={null}
flowchart LR
  A["Your server creates a Bridge session"] --> B{"Enough customer location data?"}
  B -->|"Yes: address or resolved IP"| C["Numeral calculates tax"]
  B -->|"No"| D["Hosted or embedded address collection"]
  D --> C
  C --> E["Numeral prepares Stripe Checkout"]
  E --> F["Buyer pays with Stripe"]
```

When the address or IP resolves to a tax location immediately, the returned `url` normally points directly to Stripe Checkout. When more information is required:

* `collection_mode: "hosted"` returns a Numeral-hosted URL that collects the missing fields and then continues to Stripe.
* `collection_mode: "embedded"` returns a session-scoped `client_secret` for the `<numeral-checkout>` element on your page.

Always treat the returned `url` as opaque and redirect the buyer to it without checking its hostname.

## Before you start

<Steps>
  <Step title="Connect your Stripe account">
    In the Numeral dashboard, open **Connections**, add Stripe, and complete the connection. Numeral uses the stored connection; you do not enter the Stripe secret key again when configuring checkout.
  </Step>

  <Step title="Create a checkout configuration">
    Open **Developers → Numeral for Stripe Checkout**. Use the dashboard's **Test Mode** switch to configure test and live environments separately.

    Select the Stripe connection and provide:

    * Your seller origin address
    * The billing, shipping, or service address used for tax
    * Success and cancel URLs
    * Allowed redirect origins
    * Origins allowed to embed the collector
    * A default Numeral product category

    Click **Save and publish**, then copy the resulting `brcfg_...` configuration ID.
  </Step>

  <Step title="Install the SDK">
    ```bash theme={null}
    npm install numeral-tax
    ```
  </Step>

  <Step title="Create sessions from your server">
    Keep the Numeral secret key on your server. Never expose an `sk_test_...` or live Numeral API key in browser JavaScript.
  </Step>
</Steps>

## Create a session with a complete address

If your checkout already collects the customer address, include it in the initial request. Numeral validates the location, calculates tax, and can return Stripe Checkout without an additional address step.

```ts theme={null}
import NumeralAPI from "numeral-tax";

const numeral = new NumeralAPI({
  apiKey: process.env.NUMERAL_API_KEY!,
});

const session = await numeral.tax.bridge.sessions.create({
  config_id: process.env.NUMERAL_STRIPE_CHECKOUT_CONFIG_ID!,
  collection_mode: "hosted",
  confirmation_method: "automatic",
  external_reference: "order_8421",
  checkout: {
    mode: "payment",
    line_items: [
      {
        price: "price_123",
        quantity: 1,
        product_category: "GENERAL_MERCHANDISE",
      },
    ],
    success_url: "https://store.example/success",
    cancel_url: "https://store.example/cart",
  },
  tax_context: {
    location: {
      basis: "billing_address",
      assurance: "self_attested",
      address: {
        country: "US",
        line_1: "123 W 31st St",
        city: "New York",
        province: "NY",
        postal_code: "10001",
      },
    },
  },
  "X-API-Version": "2026-03-01",
  "Idempotency-Key": crypto.randomUUID(),
});

if (!session.url) {
  throw new Error("Checkout requires additional handling");
}

// Express example
response.redirect(303, session.url);
```

<Tip>
  `collection_mode` is always required. Even when you send an address or IP, it tells Numeral how to recover if the location is incomplete or cannot be resolved confidently.
</Tip>

## Choose how Numeral gets the customer location

<CardGroup cols={2}>
  <Card title="Send an address" href="/integrations/stripe/stripe-checkout-location#send-a-complete-address" icon="address-card">
    Best when your checkout already collects billing, shipping, or service address information.
  </Card>

  <Card title="Send the customer IP" href="/integrations/stripe/stripe-checkout-location#send-the-customer-ip" icon="globe">
    Avoid an address form when the customer's public IP resolves with enough confidence.
  </Card>

  <Card title="Use hosted collection" href="/integrations/stripe/stripe-checkout-location#numeral-hosted-collection" icon="arrow-up-right-from-square">
    Redirect through a polished Numeral address step only when more location data is required.
  </Card>

  <Card title="Embed collection" href="/integrations/stripe/stripe-checkout-embedded" icon="code">
    Keep the address experience inside your checkout with the secure `<numeral-checkout>` element.
  </Card>
</CardGroup>

## Test before going live

Use a test-mode Numeral API key, a test-mode Stripe connection, and a test configuration ID together. A successful end-to-end payment progresses through these public states:

```text theme={null}
status: complete
payment_status: paid
tax_status: committed
```

Use Stripe test card `4242 4242 4242 4242`, any future expiration date, and any CVC.

<Warning>
  Test and live configurations are separate. A test Numeral API key cannot use a live Stripe connection or live `brcfg_...` configuration.
</Warning>
