Skip to main content

// 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.

Discovery is standard, so most OAuth libraries configure themselves from the metadata documents.
discovery
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.json

Register 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.

1 · send the merchant to authorize
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=…
2 · exchange the code
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.

revoke
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.

Every operation names the one scope it needs. The counts below are how many operations each scope opens, by risk tier.
ScopeReadAutomatic writeProposed write
admin:read3––
admin:write––3
ads:read9––
ads:write––6
analytics:read10––
analytics:write––2
automation:read11––
automation:write–211
catalog:read11––
catalog:write––8
costs:read4––
costs:write––3
creative:read12––
creative:write–22–
cs:read4––
cs:write–11
disputes:read1––
finance:read15––
merchant:read3––
merchant:write––2
orders:read2––
orders:write––3
promotions:read2––
promotions:write––3
read14––
reputation:read1––
research:read4––
write–42

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