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

# Quickstart

A working Meridian integration is four steps. The code below is React Router / Remix shaped, matching the Shopify app template; only the loaders are framework-specific.

Before you start, create the app in Meridian and copy its credentials. See [Credentials](/sdk-credentials).

<Steps>
  <Step title="Create one server entrypoint">
    `createMeridianApp` reads `MERIDIAN_APP_ID`, `MERIDIAN_API_KEY` and `MERIDIAN_API_URL` from the environment. Create it once and import it everywhere.

    ```ts app/meridian.server.ts theme={null}
    import { createMeridianApp } from "@the-meridian/sdk/server"

    export const meridian = createMeridianApp()
    ```

    It never throws into your app. With no credentials set, `configured` is `false` and every method returns its unconfigured result, so your app still builds and renders. See [`createMeridianApp`](/sdk-app).
  </Step>

  <Step title="Wire the install in afterAuth">
    One call registers your Shopify webhooks, reports the authentication so your install [automations](/automations) fire, reports the shop's Shopify subscriptions and their trial length (which is how apps billing through the Shopify Billing API get [trials](/free-trial#trials-on-subscriptions-you-bill-yourself) into Meridian), and attributes an [affiliate referral](/sdk-attribution) if there is one.

    ```ts app/shopify.server.ts theme={null}
    hooks: {
      afterAuth: async ({ session, request }) => {
        await meridian.afterAuth(session, { request })
      },
    },
    ```

    Meridian resolves the webhook topic set from your dashboard configuration, so you never declare topics. Passing `request` matters only if you run an affiliate program.
  </Step>

  <Step title="Mint a shop token in your loader">
    The shop token is the per-shop credential the browser uses. Mint it server-side and pass it down.

    ```ts app/routes/app.tsx theme={null}
    export const loader = async ({ request }) => {
      const { session } = await authenticate.admin(request)
      const shopToken = await meridian.mintShopToken({ shop: session.shop })
      return { shopToken }
    }
    ```

    `mintShopToken` returns `null` when Meridian is unconfigured or unreachable. Treat that as "render without Meridian", not as an error.

    Calling it in a loader is cheap: the app instance caches the handshake, so it costs one `identify` per shop per token lifetime, not one per request. On serverless hosting, where that cache is cold on every start, persist the token instead. See [Persisting the token yourself](/sdk-app#persisting-the-token-yourself).
  </Step>

  <Step title="Mount the provider">
    ```tsx app/routes/app.tsx theme={null}
    import { MeridianProvider } from "@the-meridian/sdk"

    export default function App() {
      const { shopToken } = useLoaderData<typeof loader>()

      return shopToken ? (
        <MeridianProvider shopToken={shopToken}>
          <Outlet />
        </MeridianProvider>
      ) : (
        <Outlet />
      )
    }
    ```

    The provider fetches the shop's plan, entitlements and your plan catalogue on mount, and refreshes an expired token transparently. See [`MeridianProvider`](/sdk-provider).
  </Step>
</Steps>

## Gate your first feature

Anywhere below the provider:

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

export const AdvancedReports = () => {
  const { isEnabled, loading } = useMeridian()
  if (loading) return null
  if (!isEnabled("advanced_reports")) return <UpgradePrompt />

  return <Reports />
}
```

`advanced_reports` is the feature's **key**, exactly as you typed it in the [plan builder](/introduction-13). See [Feature gating](/features).

## Add the pricing page

`MeridianPricingPage` needs a `returnUrl`, and it must be an `https` URL on the shop's own admin. Build it in the loader, where you have the session shop and your Shopify client ID:

```ts app/routes/app.pricing.tsx theme={null}
export const loader = async ({ request }) => {
  const { session } = await authenticate.admin(request)
  const returnUrl = `https://${session.shop}/admin/apps/${process.env.SHOPIFY_API_KEY}/app/pricing`
  return { returnUrl }
}
```

```tsx app/routes/app.pricing.tsx theme={null}
import { MeridianPricingPage } from "@the-meridian/sdk"

export default function Pricing() {
  const { returnUrl } = useLoaderData<typeof loader>()
  return (
    <s-page heading="Pricing">
      <s-section>
        <MeridianPricingPage returnUrl={returnUrl} />
      </s-section>
    </s-page>
  )
}
```

<Warning>
  Do not build the `returnUrl` from `request.url`, `window.location`, or your app's own hosting origin. Shopify's billing API only accepts a shop-admin URL, and the SDK throws before the call rather than letting the API reject it. See [Pricing page](/plans).
</Warning>

## Track a metered action

```ts theme={null}
const { track } = useMeridian()
await track({ eventKey: "api_calls", quantity: 1 })
```

Meridian sums the quantity over the store's current billing period and raises Shopify usage charges from your plan's terms. See [Usage tracking](/events).

## Where to go next

* [Authentication](/authentification): which credential each call uses, and why
* [`useMeridian`](/sdk-use-meridian): everything the hook exposes
* [Errors and degradation](/sdk-errors): what the SDK retries, what it swallows, and what you should handle
* [Local development](/cli): running your app against a managed developer database


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