Skip to main content
The SDK talks to Meridian’s developer-facing API at https://api.the-meridian.ai/api/public. Two credentials cover every call, and which one a call uses is decided by where the code runs, not by what it does. Both travel as Authorization: Bearer <token>.

The app API key

Your app’s secret key identifies the app. It is what mints shop tokens in the first place, and it is the only credential that can write across shops, so it never leaves your server. It authenticates:
  • identify: the handshake that upserts a shop and returns its shop token
  • the affiliate referral stash, and the app lifecycle event that fires your install automations
  • custom field values written from your backend
  • the webhook topic set the SDK reconciles per shop
Every one of those calls also carries your app ID, which Meridian cross-checks against the key. A valid key presented with someone else’s app ID is a 401 INVALID_API_KEY, not a silent write to the wrong app.

The shop token

A shop token identifies one install: this app on this shop. You mint one server-side with mintShopToken, and from then on both your server and that shop’s browser use it. It is scoped and short-lived:
  • Scope: reads and billing writes for that one shop. It cannot reach another shop’s data, cannot call the Shopify Admin API, and is not your API key.
  • Lifetime: about an hour. The provider refreshes it transparently when it expires, and calls onTokenRefreshed so you can persist the new value.
Both properties are what make it safe in the browser. Billing calls run client-side with it, so any script on the page can use it while it is valid, bounded to that one shop’s billing. Meridian resolves the Shopify Admin token on its own side, so there is no server bridge to build for subscribe, cancel or track. If you would rather enforce those writes on your own server anyway, the provider takes write overrides.

How a refresh works

An expired token comes back as 401 SHOP_TOKEN_EXPIRED. The provider rotates it against POST /auth/refresh and replays the original call once. The refresh endpoint accepts an expired token, so an idle shop does not need a fresh identify. A refresh rotates the token: the previous value stops working immediately, and anything that presents it gets a plain 401 rather than SHOP_TOKEN_EXPIRED. That is why the provider hands you the new value through onTokenRefreshed, and why the SDK itself never refreshes a token that is still live: a copy you persisted or handed to the browser keeps working for its full lifetime.

After an uninstall

An uninstall revokes the shop’s token. While the shop is uninstalled, that token answers 401 SHOP_TOKEN_REVOKED (“Shop token is no longer valid for this install.”) on every call, refresh included. A token Meridian never issued still answers a plain 401 (“Invalid shop token.”). If the shop installs the app again, the revoked token can still be refreshed until its original hour runs out. Calls made with it answer SHOP_TOKEN_EXPIRED, so the provider refreshes it like any expired token, and POST /auth/refresh returns the install’s current token without rotating it. A copy that the new session already holds keeps working. Past that hour the revoked token is refused for good, and a fresh identify replaces it. The SDK handles all of this on its own and shows the merchant nothing. A stale Shopify token is a different 401, SHOPIFY_ACCESS_TOKEN_STALE: the merchant has to relaunch the app to re-authorize. See Errors.

Transport safety

The SDK logs one warning per base URL that is neither HTTPS nor localhost, because a bearer token would otherwise be sent in plain text. It does not block the request. The warning is there to tell you the configuration is wrong before you ship it.

Rate limits

Both credentials share the same public-API budget, keyed on the bearer token: Because the key is the token, one shop’s browser cannot exhaust another shop’s budget. Exceeding a limit is a 429; the SDK retries it with backoff on the calls where a retry is safe, and createMeridianApp skips further calls locally until the Retry-After deadline passes. See Rate limits.
Last modified on October 7, 2026