Customer API
Use the Customer API to let customers see and manage their subscriptions in an app you build, such as your own iOS or Android app. Customers sign in with their Shopify customer account (email and one-time code), so they don't need a new password. Zubs runs the sign-in with Shopify's Customer Account API and gives your app a customer access token. With that token, your app reaches that customer's own subscriptions and nothing else.
Before You Start
- Your store uses Shopify's new customer accounts.
- You've created a Client ID in Shopify's Headless app and sent it to Zubs. See Generate a Client ID.
- We've confirmed that access is set up for your store.
Sign Customers In
Zubs uses OAuth 2.0 with PKCE. All sign-in endpoints take and return JSON under https://hub.zubs.app/headless-auth.
- Start.
POST /headless-auth/startwith{ "shop": "your-store.myshopify.com" }. The response containsauthUrl,verifier,nonce,stateandredirectUri. Keepverifierandnoncefor step 3. - Let the customer sign in. Open
authUrlin the system browser (ASWebAuthenticationSessionon iOS, Custom Tabs on Android). Shopify redirects toredirectUri, which has the formshop.{shopId}.app://callback, with acode. Register this URL scheme in your app. - Exchange the code.
POST /headless-auth/exchangewithcode,verifier,nonceandshop. The response containsaccessToken,refreshToken,customerIdandexpiresAt.
Store both tokens in the device's secure storage (Keychain on iOS, Keystore on Android) and never log them.
Stay Signed In and Sign Out
- Refresh before
expiresAt:POST /headless-auth/refreshwithshop,customerIdandrefreshToken. Shopify may rotate the refresh token. When the response contains a newrefreshToken, replace the stored one, or the next refresh fails. - Sign out:
DELETE /headless-auth/revokewithshop,customerIdandrefreshToken, then clear the stored tokens. - Browse before sign-in:
POST /headless-auth/storefront-tokenwith{ "shop": "…" }returns a Shopify Storefront API token for public catalogue data.
Sign-In Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | MISSING_SHOP, MISSING_PARAMETERS | A required field is missing |
| 400 | INVALID_NONCE | The nonce doesn't match the sign-in that was started |
| 401 | CLIENT_ID_NOT_CONFIGURED | Zubs doesn't have a Client ID for this store yet |
| 401 | SHOP_NOT_INSTALLED | Zubs isn't installed on this store |
| 401 | INVALID_REFRESH_TOKEN | The refresh token is wrong or was replaced; sign the customer in again |
| 404 | TOKEN_NOT_FOUND | No sign-in is stored for this customer |
Read and Manage Subscriptions
Send GraphQL requests with the customer's access token:
POST https://hub.zubs.app/api/storefront/unstable/graphql.json
curl -X POST https://hub.zubs.app/api/storefront/unstable/graphql.json \
-H "Authorization: Bearer shcat_customer_access_token" \
-H "Content-Type: application/json" \
-d '{
"query": "query Subs($id: ID!) { customer(id: $id) { subscriptionContracts(first: 20, reverse: true) { edges { node { id status nextBillingDate } } } } }",
"variables": { "id": "gid://shopify/Customer/7234567890" }
}'
/exchange returns customerId as a number. Use it as gid://shopify/Customer/<id> in GraphQL.
For a subscription's detail screen, subscriptionContractDetails returns the contract, its lines, delivery details and billing cycles in one request.
The operations available here are summarized in What the APIs Cover. Each request is checked against the signed-in customer:
- A request for another customer's subscription is rejected.
- Operations and fields that aren't available to customers are rejected with
Field "…" is not available to customer accounts. - Introspection isn't available on this endpoint. Use the explorer or the SDL file instead.
An expired or invalid token returns HTTP 401 with the code UNAUTHENTICATED. Refresh the token, and sign the customer in again if that fails.
Open the Customer Portal in Your App
The API can change subscription content, but to let customers change products, quantities or their delivery interval themselves, we recommend opening the Zubs customer portal in a web view. It already handles your stock and pricing. It's part of the customer's Shopify account. Because sign-in ran through the system browser, the customer is usually still signed in. Otherwise Shopify asks for their email and code.
- All subscriptions:
https://{YOUR_SHOPIFY_STORE_URL}/account/pages/80d48e84-1b93-4dc9-b82b-9a555222a52c - One subscription: add
/subscriptions/{subscriptionId}, using the numeric contract ID.
Enable JavaScript, cookies and DOM storage in the web view.