---
title: "Platform SDK quickstart"
description: "Create a test inventory event, embed the picker, and commit inventory from your own backend."
---

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

# Platform SDK quickstart

> **Using SeatLayer checkout? You don't need a key**
>
> Copy the embed code from [Sell & share](/start/first-event/#create-the-managed-event).
> This page is for events that take payment with your own checkout.

SeatLayer's SDK is the reserved-seating layer for a ticketing website: it draws
the venue, shows live seat availability, and returns the exact seats a buyer
picked. Adding it takes two steps: embed the picker in the browser with a public
key, then confirm the booking from your own server with a secret key. Your
platform keeps its checkout, its own payment provider, and its commercial
orders, tickets, delivery, refunds, and check-in.

## Packages

| Surface | Package | Docs |
| --- | --- | --- |
| JavaScript / TypeScript | `@seatlayer/js` | [Install the Buyer SDK](/buyer-sdk/install) |
| React | `@seatlayer/react` | [React SDK](/buyer-sdk/react) |
| Vue | `@seatlayer/vue` | [Vue SDK](/buyer-sdk/vue) |
| Angular | `@seatlayer/angular` | [Angular SDK](/buyer-sdk/angular) |
| React Native | `@seatlayer/react-native` | [React Native SDK](/buyer-sdk/react-native) |
| Flutter | `seatlayer` | [Flutter SDK](/buyer-sdk/flutter) |
| iOS | `seatlayer-ios` Swift package | [iOS SDK](/buyer-sdk/ios) |
| Android | `io.seatlayer:seatlayer-android` and `-android-compose` | [Android SDK](/buyer-sdk/android) |
| Node.js (server) | `@seatlayer/server` | [Node server SDK](/server-sdk/node) |
| Python (server) | `seatlayer` | [Python server SDK](/server-sdk/python) |
| PHP (server) | `seatlayer/seatlayer-php` | [PHP server SDK](/server-sdk/php) |
| Ruby (server) | `seatlayer` | [Ruby server SDK](/server-sdk/ruby) |
| Java (server) | `io.seatlayer:seatlayer-java` | [Java server SDK](/server-sdk/java) |
| .NET (server) | `SeatLayer` | [.NET server SDK](/server-sdk/dotnet) |
| Go (server) | `github.com/seatlayer/seatlayer-go` | [Go server SDK](/server-sdk/go) |

Current verified versions for every package live in the machine-readable
[SDK catalog](/sdk-catalog.json). Install from there rather than copying a
version number between packages.

> **Start in test mode**
>
> Use a `pk_test_…` / `sk_test_…` key pair. Sandbox events behave like live events, but bookings spend no credits. Going live is a credential swap after the flow works.

1. **Create an event**

   Publish a chart in the Designer, then create a sandbox event from your server.

```js title="server/create-event.js" {5}
const response = await fetch("https://api.seatlayer.io/v1/events", {
  method: "POST",
  headers: {
    "content-type": "application/json",
    authorization: `Bearer ${process.env.SEATLAYER_SECRET_KEY}`,
  },
  body: JSON.stringify({
    chartId: "ch_grand_theatre",
    name: "Dress rehearsal",
  }),
});

const { meta } = await response.json();
console.log(meta.key); // ev_9f3a
```

2. **Install the buyer SDK**

   Use the CDN directly or add the JavaScript package to your app.

```sh
   npm install @seatlayer/js@0
   pnpm add @seatlayer/js@0
   yarn add @seatlayer/js@0
   bun add @seatlayer/js@0
```

3. **Authorize Public-sale browser access**

   Keep the `pk_test_…` public half of the key pair you used to create the
   event, and register your buyer site's exact HTTPS origin under **Embed
   domains** in the dashboard. The public key is safe to publish in browser
   code; the matching `sk_test_…` is not.

   On first render the SDK sends the event key, public key, and browser-provided
   origin directly to SeatLayer. SeatLayer verifies their account and test/live
   mode, creates a short-lived Public-sale-only session, and returns its
   in-memory bearer together with the chart and compact inventory status. There
   is no customer-backend token round trip on this path.

   A public key cannot reveal presale, login, partner, or channel inventory.
   Those audiences still use an authenticated
   [`buyerAccessTokenProvider`](/server-api/buyer-access-sessions); an explicit
   provider or token always takes precedence over `publicKey`.

4. **Embed the picker**

   Choose the integration that matches your frontend. All variants return the same `holdId` checkout handoff.

   > **Event key or public key?**
   >
   > Replace `<YOUR_EVENT_KEY>` with your event's key. Find it at the top of the event's page in the dashboard, with a Copy button, or read `meta.key` from the `POST /v1/events` response. It starts with `ev_`.
   >
   > The two keys go in different places:
   >
   > - `event` takes the **event key** (`ev_…`). It says which event to show.
   > - `publicKey` takes your **public key** (`pk_test_…` or `pk_live_…`), from **Developer → API keys**. It says which account is asking.
   >
   > Both must come from the same account, and a `pk_test_` key only opens test events. A 404 on first load usually means one of the two is in the wrong place, the event key is still the placeholder, or the event sells through SeatLayer checkout rather than your own (those events use the hosted page, not the SDK).

### Script tag

```html title="checkout.html"
    <div id="picker" style="height: 640px"></div>
    <script src="https://cdn.seatlayer.io/seatlayer-js@0/seatlayer-buyer.js"></script>
    <script>
      const picker = new seatlayer.SeatPicker({
        container: "#picker",
        event: "<YOUR_EVENT_KEY>",
        publicKey: "<YOUR_PUBLIC_KEY>",
        onCheckout: async (_, __, handoff) => {
          await fetch("/api/checkout", {
            method: "POST",
            headers: { "content-type": "application/json" },
            body: JSON.stringify({ holdId: handoff.holdId }),
          });
        },
      });
      picker.render();
    </script>
```
### JavaScript

```js title="checkout.js"
    import { SeatPicker } from "@seatlayer/js";

    const picker = new SeatPicker({
      container: "#picker",
      event: "<YOUR_EVENT_KEY>",
      publicKey: "<YOUR_PUBLIC_KEY>",
      onCheckout: async (_, __, handoff) => {
        await fetch("/api/checkout", {
          method: "POST",
          headers: { "content-type": "application/json" },
          body: JSON.stringify({ holdId: handoff.holdId }),
        });
      },
    });

    await picker.render();
```
### React

```tsx title="Checkout.tsx"
    import { SeatPicker } from "@seatlayer/react";

    export function Checkout() {
      return (
        <SeatPicker
          event="<YOUR_EVENT_KEY>"
          publicKey="<YOUR_PUBLIC_KEY>"
          style={{ height: 640 }}
          onCheckout={async (_, __, handoff) => {
            await fetch("/api/checkout", {
              method: "POST",
              headers: { "content-type": "application/json" },
              body: JSON.stringify({ holdId: handoff.holdId }),
            });
          }}
        />
      );
    }
```

5. **Book inventory from your server**

   Resolve authoritative inventory and configured prices from the hold,
   complete your payment logic, then book inventory with the secret key. After
   success, create and deliver tickets from your own platform.

```js title="server/checkout.js" {3,15,24}
const eventKey = "<YOUR_EVENT_KEY>";
const headers = {
  authorization: `Bearer ${process.env.SEATLAYER_SECRET_KEY}`,
  "content-type": "application/json",
};

const holdResponse = await fetch(
  `https://api.seatlayer.io/v1/events/${eventKey}/holds/${holdId}`,
  { headers },
);
if (!holdResponse.ok) throw new Error("Hold is no longer active");
const hold = await holdResponse.json();

// Price from trusted hold items, not values posted by the browser.
const order = await createPaidOrder(hold.items);

const bookResponse = await fetch(
  `https://api.seatlayer.io/v1/events/${eventKey}/book`,
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      holdId,
      bookingRef: order.id,
    }),
  },
);
if (!bookResponse.ok) await handleBookingFailure(bookResponse, order);
```

> **Never expose the secret key**
>
> Browser code may receive a publishable `pk_…` for ordinary Public bootstrap,
> but never an `sk_…`. SeatLayer keeps the resulting `bse_…` in the SDK's memory;
> a private-audience provider must do the same rather than using storage or a
> URL. Keep every `sk_test_…` and `sk_live_…` in a server-side secret manager.

## Next

Use the [complete checkout example](/examples/complete-checkout) as an implementation template, then read [integration best practices](/integrations/best-practices) before going live.

If you would rather have SeatLayer run checkout, tickets and the door instead of building them yourself, follow [your first managed event](/start/first-event/) for the direct-organizer route.

Source: https://docs.seatlayer.io/start/quickstart/index.mdx
