Authentication
Learn about Cartly's authentication methods: Public API, Session, JWT, and OAuth 2.0.
Authentication Methods
| Method | Use Case | Auth Header |
|---|---|---|
| Public (none) | Storefront API — products, collections, search | X-Shop-ID: {shop_id} |
| Session Cookie | Customer accounts — orders, addresses, wishlist | __session cookie |
| JWT Bearer | Admin panel — product management, order processing | Authorization: Bearer {token} |
| OAuth 2.0 | Third-party apps — marketplace integrations | Authorization: Bearer {access_token} |
OAuth 2.0 Flow
Cartly implements the standard Authorization Code flow per RFC 6749:
- Register your app — Create an OAuth app in the Cartly admin with redirect URIs and requested scopes
- Authorization request — Redirect merchant to
/oauth/authorizewith a PKCEcode_challenge(S256, required) - User consent — Merchant approves requested permissions
- Token exchange — Exchange authorization code for access + refresh tokens
- API access — Use access token in Bearer header
Rules worth knowing
- PKCE —
code_challenge= base64url(SHA-256(code_verifier)) without=padding,code_challenge_method=S256;plainis refused at the token exchange. - Scopes — space-separated. Names Cartly doesn't know are dropped. Request only scopes registered for your app: a registered-scope mismatch makes the merchant's approval fail (the consent page shows an error) and your
redirect_urigets no callback. - Refresh tokens rotate — each
refresh_tokengrant returns a new access token AND a new refresh token; store the new refresh token, the old one is revoked.
OAuth Scopes
Available permission scopes for OAuth applications
| Name | Type | Required | Description |
|---|---|---|---|
| products:read | scope | No | View products and variants |
| products:write | scope | No | Create, update, and delete products |
| orders:read | scope | No | View orders and order history |
| orders:write | scope | No | Update order status and fulfillment |
| orders:own | scope | No | View only orders created by this app |
| customers:read | scope | No | View customer information |
| customers:write | scope | No | Create and update customers |
| discounts:read | scope | No | View discount codes and rules |
| discounts:write | scope | No | Create, update, and delete discounts |
| metafields:read | scope | No | View custom metafields |
| metafields:write | scope | No | Create, update, and delete metafields |
| webhooks:manage | scope | No | Manage webhook subscriptions |
| shop:read | scope | No | View shop settings and configuration |
| collections:read | scope | No | View product collections |
| collections:write | scope | No | Create, update, and delete collections |
| shipping:read | scope | No | View shipping zones and rates |
| shipping:write | scope | No | Manage shipping configuration |
| analytics:read | scope | No | View analytics and reports |
| inventory:read | scope | No | View inventory levels |
| inventory:write | scope | No | Set inventory levels (PUT /apps/api/inventory/:variant_id) |
| theme_extensions:write | scope | No | Add app blocks that render on the storefront (OAuth apps only) |
| checkout_extensions:write | scope | No | Add extensions that render during checkout (OAuth apps only) |
Code Examples
bash
# Step 1: send the merchant's browser to (one line):
# https://cartly.pro/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback&scope=products%3Aread%20orders%3Aread&state=RANDOM_STATE&code_challenge=BASE64URL_SHA256_OF_CODE_VERIFIER&code_challenge_method=S256
# Step 2: Exchange code for token (send the code_verifier)
curl -X POST https://cartly.pro/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"authorization_code","code":"AUTH_CODE","client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_SECRET","redirect_uri":"https://yourapp.com/callback","code_verifier":"CODE_VERIFIER"}'