---
title: "Currency and pricing"
description: "Resolve event currency, present host prices safely, and keep buyer checkout aligned with the intended server authority."
---

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

# Currency and pricing

Currency, buyer presentation, and SeatLayer's hold record are related but
separate decisions. Define the authority your checkout uses before adding a
custom price book.

## Currency precedence

| Source | Purpose |
|---|---|
| Event or organization currency | Normal order currency; travels with event data |
| SDK `currency` | Formatting fallback when event data has no currency |
| `USD` | Built-in fallback |

One hold or booking uses one ISO 4217 currency. SeatLayer does not convert
amounts between currencies, and a locale change affects formatting rather than
the amount or currency.

```js title="buyer/currency.js"
const picker = new seatlayer.SeatPicker({
  container: "#picker",
  event: "ev_9f3a",
  currency: "EUR", // event/org data wins when present
});
```

## Default: charge the inspected hold

For the simplest and safest checkout, inspect the hold from your backend and
calculate the payment from its `unitPrice`, `currency`, and `quantity`.

```ts title="server/order-total.ts"
const hold = await inspectHold(eventKey, holdId);

const total = hold.items.reduce(
  (sum, item) => sum + item.unitPrice * item.quantity,
  0,
);

assertOneCurrency(hold.items);
await createPayment({ amount: total, currency: hold.items[0].currency });
```

This makes the chart price snapshot, SeatLayer reports, and your charged amount
agree.

## Host price books

`SeatPicker.pricing` can make your application price-authoritative for the
buyer presentation and SDK checkout handoff:

```js title="buyer/member-pricing.js"
const picker = new seatlayer.SeatPicker({
  container: "#picker",
  event: "ev_9f3a",
  pricing: {
    prices: {
      vip: 150,
      standard: {
        base: 60,
        tiers: {
          early: 45,
          door: 75,
        },
      },
    },
    formatter: (amount, currency) => `${amount} ${currency}`,
  },
  onCheckout: (_hold, _seats, handoff) => {
    startCheckout({
      holdId: handoff.holdId,
      displayedTotal: handoff.total,
    });
  },
});
```

`prices` accepts a flat category amount or a base amount plus tier overrides.
`formatter` changes rendered money text. The picker applies the override to
displayed totals and the `CheckoutHandoff` it gives your callback.

> **The hold retains the chart price**
>
> A host override does not rewrite the `unitPrice` stored in SeatLayer's hold.
> A fresh server inspection still returns the chart-authoritative snapshot.
> Treat the browser handoff as context, never as trusted payment input.

## Choose one server policy

### Chart-priced checkout

Ignore browser-posted totals. Inspect the hold and charge its recorded line
items. This keeps SeatLayer's amount reporting aligned with payment.
### Host-priced checkout

Resolve the same category and tier ids against your own server-side price
book. Validate eligibility, currency, discounts, and tax there. Record both
your charged amount and SeatLayer's inspected amount because SeatLayer
reports will continue to reflect the chart snapshot.

Never trust a custom amount posted from the browser—even if it matches the
`CheckoutHandoff`. Send the opaque `holdId` plus your own authenticated cart or
price-context identifier. Recompute the intended amount on the server.

## Prevent mismatches

- Keep category keys and tier ids stable across the chart and host price book.
- Version promotional and membership rules so checkout can reproduce them.
- Reject mixed currencies before creating a payment.
- Store the hold id, booking reference, price-book version, and charged amount.
- Decide how refunds and reports reconcile when host and chart prices differ.
- Test resumed and extended holds; a client refresh must not change eligibility.
- Display taxes and fees separately unless they are intentionally part of unit
  price.

## Money units

SeatLayer chart and hold examples use major units, such as `45` for 45.00.
Payment providers often require minor units. Convert once on your server using a
currency-aware library; do not assume every currency has two decimal places.

Continue to [holds and checkout](/buyer-sdk/holds-and-checkout),
[ticket tiers](/buyer-sdk/ticket-tiers), or the
[complete checkout example](/examples/complete-checkout).

Source: https://docs.seatlayer.io/customization/currency-and-pricing/index.mdx
