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

# Customer location and address validation

> Choose between a complete address, customer IP, Numeral-hosted collection, or embedded address collection.

Numeral for Stripe Checkout accepts the best customer location signal your application already has. You can send a complete address, send the customer's public IP address, or provide a country and let Numeral collect only the missing fields.

| Integration path      | What your server sends                                                     | Buyer experience                                                                      |
| --------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Complete address      | Country and the available street, city, state or province, and postal code | Usually continues directly to Stripe                                                  |
| Customer IP           | The customer's public IPv4 or IPv6 address                                 | Usually continues directly to Stripe when the IP resolves confidently                 |
| Numeral hosted        | A country or partial address with `collection_mode: "hosted"`              | Numeral collects missing fields on `checkout.numeralhq.com`, then continues to Stripe |
| Embedded on your site | A country or partial address with `collection_mode: "embedded"`            | The secure Numeral collector appears inside your checkout                             |

## Address validation

Numeral validates customer location before finalizing tax. For example, a New York postal code paired with California as the state is not silently accepted as a taxing jurisdiction.

* State or province and postal code are collected together where both are needed.
* Mismatches remain correctable in the Numeral collector instead of ending the checkout.
* Numeral asks only for fields the tax calculation still requires.
* If a merchant-provided address is invalid, the server receives a structured API error that can be shown in the merchant's own address form.
* Buyer address and tax ID values are not included in merchant-facing collector events.

<Note>
  Use ISO 3166-1 alpha-2 country codes such as `US`, `CA`, `GB`, or `DE`. Use the standard state, province, or region abbreviation when one exists.
</Note>

## Send a complete address

Use the address path when your application already collects billing, shipping, or service address information.

<CodeGroup>
  ```ts Node.js theme={null}
  tax_context: {
    location: {
      basis: "shipping_address",
      assurance: "self_attested",
      address: {
        country: "US",
        line_1: "123 W 31st St",
        city: "New York",
        province: "NY",
        postal_code: "10001",
      },
    },
  }
  ```

  ```go Go theme={null}
  TaxContext: numeraltax.TaxBridgeSessionNewParamsTaxContext{
      Location: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationUnion{
          OfTaxBridgeSessionNewsTaxContextLocationObject: &numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObject{
              Basis:     "shipping_address",
              Assurance: "self_attested",
              Address: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObjectAddress{
                  Country:    "US",
                  Line1:      numeraltax.String("123 W 31st St"),
                  City:       numeraltax.String("New York"),
                  Province:   numeraltax.String("NY"),
                  PostalCode: numeraltax.String("10001"),
              },
          },
      },
  },
  ```
</CodeGroup>

Choose the `basis` that matches how your configuration and business establish the place of sale:

* `billing_address`
* `shipping_address`
* `service_address`
* `merchant_asserted`

When this address resolves successfully, Numeral calculates tax and the session `url` normally points directly to Stripe Checkout.

## Send the customer IP

If your server knows the customer's public IP address, send it as an alternative to `address`. Do not send both in the same location object.

<CodeGroup>
  ```ts Node.js theme={null}
  const customerIp = getCustomerIpFromTrustedProxy(request);

  const session = await numeral.tax.bridge.sessions.create({
    config_id: process.env.NUMERAL_STRIPE_CHECKOUT_CONFIG_ID!,
    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",
        ip: { value: customerIp },
      },
    },
    "X-API-Version": "2026-03-01",
    "Idempotency-Key": crypto.randomUUID(),
  });
  ```

  ```go Go theme={null}
  session, err := client.Tax.Bridge.Sessions.New(ctx, numeraltax.TaxBridgeSessionNewParams{
      XAPIVersion:        numeraltax.TaxBridgeSessionNewParamsXAPIVersion2026_03_01,
      IdempotencyKey:     numeraltax.String("checkout_request_8421"),
      ConfigID:           os.Getenv("NUMERAL_STRIPE_CHECKOUT_CONFIG_ID"),
      CollectionMode:     numeraltax.TaxBridgeSessionNewParamsCollectionModeHosted,
      ConfirmationMethod: numeraltax.TaxBridgeSessionNewParamsConfirmationMethodAutomatic,
      Checkout: numeraltax.TaxBridgeSessionNewParamsCheckout{
          Mode: "payment",
          LineItems: []numeraltax.TaxBridgeSessionNewParamsCheckoutLineItem{{
              Price: "price_123", Quantity: 1,
          }},
          SuccessURL: numeraltax.String("https://store.example/success"),
          CancelURL:  numeraltax.String("https://store.example/cart"),
      },
      TaxContext: numeraltax.TaxBridgeSessionNewParamsTaxContext{
          Location: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationUnion{
              OfTaxBridgeSessionNewsTaxContextLocationObject2: &numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObject2{
                  Basis: "billing_address",
                  IP: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObject2IP{
                      Value: customerIP,
                  },
              },
          },
      },
  })
  if err != nil {
      return err
  }
  ```
</CodeGroup>

If IP resolution provides enough location data, the buyer can continue directly to Stripe without entering an address. If it does not, the selected `collection_mode` obtains the missing information.

<Warning>
  Capture the buyer's IP on your server from a trusted platform or proxy header. Do not send your server's outbound IP, and do not trust an arbitrary IP value submitted by browser JavaScript.
</Warning>

## Numeral-hosted collection

Hosted collection is the simplest fallback when your checkout does not collect an address. Send the known country or partial address and set `collection_mode` to `hosted`.

<CodeGroup>
  ```ts Node.js theme={null}
  const session = await numeral.tax.bridge.sessions.create({
    config_id: process.env.NUMERAL_STRIPE_CHECKOUT_CONFIG_ID!,
    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(),
  });

  response.redirect(303, session.url!);
  ```

  ```go Go theme={null}
  session, err := client.Tax.Bridge.Sessions.New(ctx, numeraltax.TaxBridgeSessionNewParams{
      XAPIVersion:        numeraltax.TaxBridgeSessionNewParamsXAPIVersion2026_03_01,
      IdempotencyKey:     numeraltax.String("checkout_request_8421"),
      ConfigID:           os.Getenv("NUMERAL_STRIPE_CHECKOUT_CONFIG_ID"),
      CollectionMode:     numeraltax.TaxBridgeSessionNewParamsCollectionModeHosted,
      ConfirmationMethod: numeraltax.TaxBridgeSessionNewParamsConfirmationMethodAutomatic,
      Checkout: numeraltax.TaxBridgeSessionNewParamsCheckout{
          Mode: "payment",
          LineItems: []numeraltax.TaxBridgeSessionNewParamsCheckoutLineItem{{
              Price: "price_123", Quantity: 1,
          }},
          SuccessURL: numeraltax.String("https://store.example/success"),
          CancelURL:  numeraltax.String("https://store.example/cart"),
      },
      TaxContext: numeraltax.TaxBridgeSessionNewParamsTaxContext{
          Location: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationUnion{
              OfTaxBridgeSessionNewsTaxContextLocationObject: &numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObject{
                  Basis: "billing_address",
                  Address: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObjectAddress{
                      Country: "US",
                  },
              },
          },
      },
  })
  if err != nil {
      return err
  }

  http.Redirect(response, request, session.URL, http.StatusSeeOther)
  ```
</CodeGroup>

The buyer is sent to a Numeral-hosted address validation step and then automatically continues to Stripe Checkout. The returned URL is stable for idempotent replay and does not contain a session capability or buyer information.

<Tip>
  Redirect to `session.url` without inspecting whether it points to Numeral or Stripe. This keeps the fast path and collection fallback identical in your application code.
</Tip>

### Brand the hosted page

The hosted address page can show your business name, logo, colors, intro copy, return link label, and default locale. Branding lives on the checkout configuration, so session creation does not change: the `config_id` you already send selects the look.

You can customize:

* `branding.display_name`, `branding.logo`, and `branding.custom_text` (intro message and return link label)
* `appearance.variables` and `appearance.rules` for colors, fonts, radius, and form controls
* `locale_default` for the page language and number formatting

The "Secure checkout" label, step titles, button labels, tax summary labels, the footer sentence, and "Powered by Numeral" stay fixed.

In the dashboard, open **Developers → Numeral for Stripe Checkout** and use the **Branding** section. **Use Stripe branding** prefills the business name and primary color from your connected Stripe account. Through the API, add the keys to `draft_payload` and publish:

```json theme={null}
{
  "draft_payload": {
    "...": "existing payload",
    "locale_default": "en-US",
    "appearance": { "variables": { "colorPrimary": "#0b57d0" } },
    "branding": {
      "display_name": "Acme Outdoor",
      "logo": "brast_3f1c9d2e-5b0a-4c6e-9d21-7a8f0b1c2d3e",
      "custom_text": {
        "intro": { "message": "We need your address to calculate sales tax before payment." },
        "return_link": { "message": "Back to Acme" }
      }
    }
  }
}
```

<Note>
  Branding changes take effect after you publish. Sessions created after the publish use the new version. Sessions already in flight keep the version they were created with.
</Note>

See [Branding and appearance](/integrations/stripe/stripe-checkout-branding) for field bounds, publish rules, logo upload, and error codes.

## Embedded collection on your site

Embedded mode keeps the location step inside your checkout. Your server creates the session, then passes only the session ID and session-scoped `client_secret` to your browser.

<CodeGroup>
  ```ts Node.js theme={null}
  const session = await numeral.tax.bridge.sessions.create({
    config_id: process.env.NUMERAL_STRIPE_CHECKOUT_CONFIG_ID!,
    collection_mode: "embedded",
    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(),
  });

  return Response.json({
    sessionId: session.id,
    clientSecret: session.client_secret,
  });
  ```

  ```go Go theme={null}
  session, err := client.Tax.Bridge.Sessions.New(ctx, numeraltax.TaxBridgeSessionNewParams{
      XAPIVersion:        numeraltax.TaxBridgeSessionNewParamsXAPIVersion2026_03_01,
      IdempotencyKey:     numeraltax.String("checkout_request_8421"),
      ConfigID:           os.Getenv("NUMERAL_STRIPE_CHECKOUT_CONFIG_ID"),
      CollectionMode:     numeraltax.TaxBridgeSessionNewParamsCollectionModeEmbedded,
      ConfirmationMethod: numeraltax.TaxBridgeSessionNewParamsConfirmationMethodAutomatic,
      Checkout: numeraltax.TaxBridgeSessionNewParamsCheckout{
          Mode: "payment",
          LineItems: []numeraltax.TaxBridgeSessionNewParamsCheckoutLineItem{{
              Price: "price_123", Quantity: 1,
          }},
          SuccessURL: numeraltax.String("https://store.example/success"),
          CancelURL:  numeraltax.String("https://store.example/cart"),
      },
      TaxContext: numeraltax.TaxBridgeSessionNewParamsTaxContext{
          Location: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationUnion{
              OfTaxBridgeSessionNewsTaxContextLocationObject: &numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObject{
                  Basis: "billing_address",
                  Address: numeraltax.TaxBridgeSessionNewParamsTaxContextLocationObjectAddress{
                      Country: "US",
                  },
              },
          },
      },
  })
  if err != nil {
      return err
  }

  _ = json.NewEncoder(response).Encode(map[string]string{
      "sessionId":    session.ID,
      "clientSecret": session.ClientSecret,
  })
  ```
</CodeGroup>

Continue with [Embed address collection](/integrations/stripe/stripe-checkout-embedded) to mount the collector and handle its events.

## Selecting the right path

<AccordionGroup>
  <Accordion title="My checkout already collects a full address">
    Send the address in the initial request. This gives the fastest buyer experience and lets Numeral validate the address before Stripe Checkout is created.
  </Accordion>

  <Accordion title="I know the customer's public IP but do not collect an address">
    Send `tax_context.location.ip`. Choose hosted or embedded collection as the fallback in case the IP does not resolve with enough confidence.
  </Accordion>

  <Accordion title="I want the least frontend work">
    Use hosted collection. Your application only redirects to the opaque URL returned by Numeral.
  </Accordion>

  <Accordion title="I want address collection to remain inside my checkout">
    Use embedded collection. The Numeral custom element renders a secure cross-origin iframe and exposes redacted lifecycle events to your page.
  </Accordion>
</AccordionGroup>
