// developers · authentication
Two credentials, one set of scopes.
An API key for your own scripts, or OAuth 2.1 for an app that acts for someone else. Both carry the same scopes, and both are checked on every call.
// choose
Which credential you need.
API key — your own code
Create one in Magistry under Settings → Developers. It looks like mag_sk_live_… and is sent as Authorization: Bearer. A key belongs to one store and carries the scopes you picked when you created it.
To try the API without touching a real store, use “Try the API on demo data” on the same page. It issues a mag_sk_sbx_… key on a private copy of demo data, which expires on its own.
OAuth 2.1 — an app for other merchants
Authorization code with PKCE (S256 only). The merchant signs in, picks the stores the app may reach and approves the scopes. Your app then runs as an app: it reaches only the stores it was granted, writes only if write access was granted, and never more than the person who granted it can.
// oauth
The authorization code flow.
curl https://app.magistry.io/.well-known/oauth-protected-resource
curl https://app.magistry.io/.well-known/oauth-authorization-server
curl https://app.magistry.io/.well-known/jwks.jsonRegister with a client metadata document. Your client_id is an https URL that serves your client metadata (name, redirect URIs, logo). There is no registration call and no client secret to store.
Dynamic Client Registration (POST /api/oauth/register) still works but was deprecated on 6 September 2026 and stops accepting new registrations on 6 September 2027. Client ids it already issued keep working.
GET https://app.magistry.io/api/oauth/authorize
?response_type=code
&client_id=https://your-app.example/oauth/client.json
&redirect_uri=https://your-app.example/callback
&scope=orders:read catalog:read
&code_challenge=<S256 of your verifier>
&code_challenge_method=S256
&state=…curl -X POST https://app.magistry.io/api/oauth/token \
-d grant_type=authorization_code \
-d code=… \
-d redirect_uri=https://your-app.example/callback \
-d client_id=https://your-app.example/oauth/client.json \
-d code_verifier=…// tokens
Lifetimes and revocation.
- Authorization code
- 10 minutes, single use
- Access token
- 1 hour, an ES256 JWT; the kid is the key's RFC 7638 thumbprint
- Refresh token
- 30 days, rotated on every use
- Enterprise token exchange
- ID-JAG (RFC 8693) for managed sign-in; issues no refresh token
- Introspection and revocation
- RFC 7662 and RFC 7009 at /api/oauth/introspect and /api/oauth/revoke
Revocation works per grant, not per token. When a merchant disconnects your app, or you revoke, every access token issued under that grant is refused from that moment, including ones that have not expired yet. If the revocation check itself cannot run, the call is refused rather than allowed.
Who can see what, and how that is enforced, is on the Trust Center.
curl -X POST https://app.magistry.io/api/oauth/revoke \
-d token=<refresh token> \
-d client_id=https://your-app.example/oauth/client.json// scopes
28 scopes, each named for what it reaches.
| Scope | Read | Automatic write | Proposed write |
|---|---|---|---|
admin:read | 3 | – | – |
admin:write | – | – | 3 |
ads:read | 9 | – | – |
ads:write | – | – | 6 |
analytics:read | 10 | – | – |
analytics:write | – | – | 2 |
automation:read | 11 | – | – |
automation:write | – | 21 | 1 |
catalog:read | 11 | – | – |
catalog:write | – | – | 8 |
costs:read | 4 | – | – |
costs:write | – | – | 3 |
creative:read | 12 | – | – |
creative:write | – | 22 | – |
cs:read | 4 | – | – |
cs:write | – | 1 | 1 |
disputes:read | 1 | – | – |
finance:read | 15 | – | – |
merchant:read | 3 | – | – |
merchant:write | – | – | 2 |
orders:read | 2 | – | – |
orders:write | – | – | 3 |
promotions:read | 2 | – | – |
promotions:write | – | – | 3 |
read | 14 | – | – |
reputation:read | 1 | – | – |
research:read | 4 | – | – |
write | – | 4 | 2 |
Build on the same tools the product uses.
Create a sandbox key on demo data, or start free and connect a real store.
MCP + REST · OAuth 2.1 or API keys · every call audited
