---
title: "Connect a Shopify store with a custom-app Admin token"
method: POST
path: "/v1/connect/shopify/token"
tags: ["Connect"]
---

# Connect a Shopify store with a custom-app Admin token

`POST /v1/connect/shopify/token`

Token-paste alternative to the OAuth flow: connect a store using the
Admin API access token of a custom app the merchant created in their
own Shopify admin (Settings → Apps and sales channels → Develop apps,
with the `read_content`/`write_content` scopes). Use this when the
one-click OAuth connect is unavailable or when your users prefer not
to install a third-party app on their store. The token is validated
against the store before anything is saved; custom-app tokens do not
expire. Connecting the same profile to a store again replaces the
stored token in place.

## Request body

- object
  - `profileId` string, required — Your Zernio profile ID (get from /v1/profiles).
  - `shop` string, required — The myshopify.com store domain, e.g. `your-store.myshopify.com` (the bare `your-store` prefix is accepted too).
  - `accessToken` string, required — Admin API access token of the merchant-created custom app (starts with `shpat_`).

## Response `200`

Store connected as a platform account

- object
  - `account` object
    - `_id` string
    - `platform` 'shopify'
    - `username` string — The myshopify.com domain of the connected store.
    - `displayName` string
    - `profileId` string

## Other responses

- `400` — Invalid `profileId` format, `shop` is not a myshopify.com store domain, or Shopify rejected the access token for that store.
- `401` — Unauthorized
- `402` — Payment method or enterprise contract required. The authenticated account hit a billing gate before the connection could proceed. Three reasons: - `free_tier_exceeded`: the team has connected more accounts than the free tier allows. Add a payment method on the dashboard to continue (the user will be billed per additional connected account). - `twitter_passthrough`: connecting an X (Twitter) account requires a card on file from day one because X API calls incur real per-call pass-through costs. Applies to the 1st X account, not just the 3rd+. - `enterprise_required`: the team is on an enterprise contract with a negotiated connected-account cap and has reached it. Self-service teams have NO connection cap (the $1/account rate continues at any scale), so this reason can only fire for teams whose contract sets an explicit limit. `dashboard_url` deep-links to the enterprise contact page rather than the billing tab. The end-user already has a card on file; this gate is about contract terms, not card collection. SDK consumers should switch on `reason` to render the right prompt. For `free_tier_exceeded` and `twitter_passthrough`, redirect the end-user to `dashboard_url` to add a payment method via Zernio's hosted Stripe Setup Checkout. For `enterprise_required`, redirect to `dashboard_url` (the enterprise contact form) to adjust the contract's limit.
- `403` — API key does not have access to this profile.

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/revisions/15e893e69e8c/schema)
