---
title: "Raw map API"
description: "Use SeatLayerView and SeatLayerController from React Native 0.3.4 when your application intentionally owns every buyer control and hold transition."
---

This page is the focused reference for the preserved raw-map API shipped in
`@seatlayer/react-native@0.3.4`.

<Aside type="note" title="Raw means your UI">
  The map renders and mutates authoritative SeatLayer inventory. Your app owns
  selection explanation, confirmation, cart, hold timing, checkout, errors,
  test-mode disclosure, and any required attribution around it.
</Aside>

## Public component contract

```tsx
<SeatLayerView
  controller={controller}
  configuration={configuration}
  style={{ flex: 1 }}
  reloadKey={reloadKey}
  onReady={handleReady}
  onLoadError={handleLoadError}
/>
```

`controller` and `configuration` are required. `style`, `reloadKey`, `onReady`,
and `onLoadError` are optional. The component is not a `forwardRef` surface.

Use `reloadKey` only for an intentional new chart generation. Ordinary React
rerenders should keep both the controller and configuration identity unchanged.

## Buyer access

The package's dependable path is a renewable provider backed by your
server:

```tsx
import type { SeatLayerConfiguration } from '@seatlayer/react-native';

const configuration = useMemo<SeatLayerConfiguration>(
  () => ({
    event,
    locale: 'en',
    currency: 'USD',
    maxSelection: 6,
    buyerAccessTokenProvider: ({ reason }) =>
      buyerBackend.mintSeatLayerAccess(reason),
  }),
  [event],
);
```

The provider returns a short-lived `BuyerAccessToken` in memory. An explicit
one-shot `buyerAccessToken` is also supported, but a provider can renew after
expiry or authorization failure without rebuilding the view.

Create the native buyer-access session on your backend through
[buyer access sessions](/server-api/buyer-access-sessions), return only its
short-lived token to the provider, and treat SDK access details as opaque.

For Public inventory, use the matching publishable key:

```tsx
const configuration = useMemo<SeatLayerConfiguration>(
  () => ({ event, publicKey: 'pk_test_your_public_key' }),
  [event],
);
```

### Configuration map

| Concern | Configuration fields |
| --- | --- |
| Identity/access | `event`, `publicKey`, `buyerAccessToken`, `buyerAccessTokenProvider` |
| Selection policy | `maxSelection`, `selectedObjects`, `selectableObjects`, `numberOfPlacesToSelect`, `selectionValidators` |
| Presentation | `locale`, `messages`, `currency`, `colorblindSafe`, `initialView`, `showsWebSeatTooltip` |
| Deadlines/diagnostics | `commandTimeoutMs`, `handshakeTimeoutMs`, `hostInfo` |
| Non-default API | `apiBase`; leave unset for SeatLayer production |

See the
[tagged `SeatLayerConfiguration` declaration](https://github.com/seatlayer/seatlayer-react-native/blob/v0.3.4/src/types.ts)
for exact types and payload models.

## Subscribe to controller events

`controller.on` returns an unsubscribe function, so it fits directly into a
React effect:

```tsx
useEffect(() => {
  const stopSelection = controller.on('selectionChanged', setSelectedSeats);
  const stopExpiry = controller.on('holdExpired', returnBuyerToMap);
  const stopError = controller.on('error', reportSeatLayerError);

  return () => {
    stopSelection();
    stopExpiry();
    stopError();
  };
}, [controller]);
```

Event payloads are typed. Unknown future events are retained rather than
crashing an older application.

| Event | Payload/meaning |
| --- | --- |
| `selectionChanged` | Full `SelectedSeat[]`; replace, do not append to, host state |
| `selectionValidityChanged` | `SelectionValidity` for exact-count and validator UI |
| `holdChanged`, `holdRestored`, `holdExpired` | Authoritative hold state and expiry |
| `accessExpired`, `accessUnavailable` | Refresh outcome or private-access refusal |
| `selectedObjectsUnavailable` | Labels/reason that must be removed from buyer UI |
| `error`, `unknownEvent` | Typed operational error or forward-compatible raw event |

The host explicitly calls `hold()` and hands only `holdId` to its backend.
No map event is booking authority or should launch raw-map checkout by itself.

## Common command groups

These are common task groups, not an exhaustive API substitute.

| Group | Methods |
| --- | --- |
| Read | `getSelection`, `getSelectionValidity`, `getCurrentHold`, `getGAAreas`, `getFloors`, `getViewMode` |
| Select | `selectObjects`, `deselectObjects`, `clearSelection`, `selectCategories`, `deselectCategories`, `setSelectableObjects`, `setMaxSelection`, `setSeatTier` |
| Hold | `hold`, `resumeHold`, `extendHold`, `release`, `releaseLabels`, `bestAvailable`, `holdGA` |
| Access | `refreshAccess` |
| Map | `setFloor`, `setColorblindSafe`, `setViewMode`, `zoomIn`, `zoomOut`, `zoomToFit` |
| Session | `destroy` |

Use the
[tagged controller source](https://github.com/seatlayer/seatlayer-react-native/blob/v0.3.4/src/controller.ts)
for exact arguments, returns, and every method in `0.3.4`. Gate optional host
controls from negotiated bundle capabilities and handle
`unsupported_command`; method presence alone does not prove an Event supports
the feature.

Commands return promises. Catch `SeatLayerError` at the awaited call so a sold
seat, incompatible capability, timeout, or destroyed session stays attached to
the action that failed.

```tsx
try {
  const hold = await controller.bestAvailable(4);
  if (hold) await checkoutBackend.begin({ holdId: hold.holdId });
} catch (error) {
  if (error instanceof SeatLayerError) {
    showInventoryMessage(error.code, error.message);
  }
}
```

## Hold ownership

- A hold is temporary inventory ownership, not a booking.
- Keep its opaque ID out of logs and analytics.
- Call `resumeHold(holdId)` only when restoring a checkout your product owns.
- Treat `holdExpired` as authoritative even if an in-app countdown had time
  remaining.
- Send only `holdId` to the server. Cart lines and totals in the app are for
  display, not payment authority.

## View and gesture requirements

- Give `SeatLayerView` a definite size.
- Do not mount it in a parent that competes for pan or pinch gestures.
- Keep application overlays accessible without intercepting the map
  accidentally.
- Use the SDK's typed camera and floor commands; do not forward raw touch
  coordinates into the map.

## Cleanup

`useSeatLayerController()` owns controller cleanup for the hook lifecycle. If a
different integration constructs and owns a controller directly, destroy that
session when its screen is permanently finished. Do not send commands after
destruction.

## Related pages

- [React Native SDK overview](/buyer-sdk/react-native)
- [Native picker and custom layouts](/buyer-sdk/react-native/native-picker)
- [Holds and checkout](/buyer-sdk/holds-and-checkout)
- [Lifecycle and foreground recovery](/buyer-sdk/react-native#lifecycle-and-recovery)
- [Shared troubleshooting matrix](/buyer-sdk/mobile#troubleshooting)
- [Tagged example](https://github.com/seatlayer/seatlayer-react-native/tree/v0.3.4/example)
- [Tagged changelog](https://github.com/seatlayer/seatlayer-react-native/blob/v0.3.4/CHANGELOG.md)