> ## Documentation Index
> Fetch the complete documentation index at: https://help.the-meridian.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# MeridianProvider

`MeridianProvider` is the one component every React integration needs. Mount it once, high in your embedded app's tree, and everything below it can read the shop's plan and drive billing.

```tsx theme={null}
import { MeridianProvider } from "@the-meridian/sdk"

<MeridianProvider shopToken={shopToken}>
  <Outlet />
</MeridianProvider>
```

## What it does on mount

One request to `/me` fetches the shop's CRM record, its resolved entitlements and your active plans together, so a gate check further down the tree is synchronous.

`loading` stays `true` until that request resolves. Render skeletons or `null` while it does; gating on an unresolved snapshot reads as ungated and will flash the upgrade prompt at a paying merchant.

It also captures the staff member currently using your app, in a background call that never blocks your render. This needs your Shopify client id and secret in **App Settings**. See [Automatic contact capture](/sdk-identify#automatic-contact-capture).

## Props

| Prop | Type | Notes |
| - | - | - |
| `shopToken` | `string` | Required. Minted server-side with `mintShopToken` |
| `baseUrl` | `string` | API root override. Leave unset in production |
| `onTokenRefreshed` | `(next) => void` | Fired after the provider rotates an expired token. Persist the new value if you cache it |
| `onShopifyAccessTokenStale` | `() => void` | Fired when the merchant must re-authorize. Defaults to reloading the page |
| `onSubscribe`, `onCancelSubscription`, `onUpdateUsageCap`, `onTrack` | functions | Route that write through your own server instead of calling Meridian directly |

Passing a new `shopToken` switches the token every later call uses, but it does not re-read on its own. Call `refresh()` if you need the snapshot to follow. The handler props are read live, so inline closures are fine and never stall the provider.

## Token refresh, handled for you

A shop token lasts about an hour. When a call comes back expired, the provider rotates the token, replays that one call, and updates its own state. Your component sees a slightly slower call, not an error.

A token revoked by an uninstall (`SHOP_TOKEN_REVOKED`) goes through the same refresh. Once the shop has reinstalled, Meridian answers it with the install's current token, so a page your server rendered with an old token still loads. See [After an uninstall](/authentification#after-an-uninstall).

Persist the rotated token from `onTokenRefreshed` if your app caches it. Otherwise the next server render mints a fresh one.

## When the merchant has to re-authorize

Meridian bills a shop by reading your app's own Shopify offline session. If that session is gone or its refresh keeps failing, Meridian answers `SHOPIFY_ACCESS_TOKEN_STALE` and no retry can fix it. Only the merchant relaunching the app can.

The provider handles this **once per mount**, so a page with several failing calls does not reload in a loop. By default it reloads the window, which in an embedded app puts the merchant back through Shopify's authorization. Pass `onShopifyAccessTokenStale` to show your own prompt instead:

```tsx theme={null}
<MeridianProvider
  shopToken={shopToken}
  onShopifyAccessTokenStale={() => setNeedsReauth(true)}
>
```

The error is still thrown after your handler runs, so the calling component can react too.

## Routing writes through your own server

By default the provider calls Meridian directly from the browser with the shop token. Some apps prefer billing actions to be enforced server-side. Pass an override and the provider calls your handler instead:

```tsx theme={null}
<MeridianProvider
  shopToken={shopToken}
  onSubscribe={(planId, returnUrl, interval, code) =>
    myServer.subscribe(planId, returnUrl, interval, code)}
  onCancelSubscription={() => myServer.cancel()}
  onUpdateUsageCap={(input) => myServer.updateCap(input)}
  onTrack={(input) => myServer.track(input)}
>
```

Overrides replace the network call and nothing else: the provider still refreshes state after a cancel, and still resolves the `returnUrl` before handing it to you. Reads and discount validation are not overridable.

## Running unconfigured

`mintShopToken` returns `null` when Meridian has no credentials or is unreachable, so mount the provider conditionally and render your app without it in that case. If you mount your tree without the provider, the SDK's own page components degrade to an empty state and log one warning naming the likely cause, rather than crashing the render.

For code of your own that must survive both cases, `useOptionalMeridian()` returns `null` instead of throwing. See [`useMeridian`](/sdk-use-meridian#useoptionalmeridian).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.