/v1 request requires both:
- An OAuth 2.0 access token in the
Authorizationheader (scheme:DPoP, notBearer). - A DPoP proof JWT in the
DPoPheader — signed fresh per request with a key only your merchant holds.
/v1 routes:
- OAuth access tokens (DPoP-bound) — for server-to-server integrations.
- WorkOS portal JWTs — issued to users signed in to the merchant dashboard.
Glossary
Generating credentials
Sign in to the merchant portal, go to Settings → API Credentials, and click Create credentials. The portal:- Generates an ES256 (P-256) DPoP keypair in your browser using WebCrypto. The private key never leaves your device.
- Submits the public JWK to Anton.
- Returns
client_id,client_secret, and the private key in PEM + JWK form — all three shown once. Copy them or download the.pem.
payouts, intelligence) fixed at creation time. Unless you narrow it, a new credential defaults to your account’s full capability set. Scopes are immutable after creation — create a new credential and revoke the old one to change them. Calls outside a credential’s scope fail with 403 insufficient_scope; calls outside your account’s capabilities fail with 403 capability_required. See Capabilities & Scopes.
Sandbox credentials are issued by app.antonpayments.dev and only authenticate against api.antonpayments.dev. Production credentials similarly only work against api.antonpayments.com.
Token endpoint
POST /oauth/token exchanges your (client_id, client_secret) plus a DPoP proof for an access token.
Request:
Content-Type: application/x-www-form-urlencodedAuthorization: Basic <base64(client_id:client_secret)>(body fallback also accepted:client_id+client_secretas form fields)DPoP: <proof JWT>— required, withhtm=POST,htu=https://api.antonpayments.dev/oauth/token, freshiatandjti, and noathclaim.- Body:
grant_type=client_credentials
expires_in is in seconds. Cache the token until exp - 60s then re-mint. There are no refresh tokens — call the endpoint again with your secret.
scope echoes the credential’s grants, space-delimited (RFC 6749 §3.3) — the same values are embedded in the access token’s scope claim. There is no scope request parameter: tokens always carry exactly the scopes the OAuth client was created with. See Capabilities & Scopes.
Errors (RFC 6749 §5.2 envelope):
Making authenticated requests
Every/v1 call needs both headers:
htm— HTTP method (POST,GET, etc.)htu— request URL, scheme + host + path only (no query, no fragment)iat— Unix timestamp, must be within ±60 seconds of Anton’s clockjti— unique identifier; Anton rejects replays within a 5-minute windowath— base64url(SHA-256(access_token))
jwk MUST hash to the jkt you registered):
curl quickstart
The script below mints a token and callsGET /v1/beneficiaries against sandbox. It shells out to openssl, jq, and a small Python helper for ECDSA signature conversion — adapt to your language as needed; production clients should use a JOSE library rather than this verbose shell version.
Token caching
- Cache an access token until
exp - 60 seconds. Don’t refresh on every call — it’s wasted round-trips. - On
401 invalid_token, force-refresh once (the previous token may have expired between mint and use). - DPoP proofs are not cacheable — generate a fresh one for every request.
Troubleshooting
Security model
DPoP defends against bearer-token theft. A leaked access token alone is useless without the matching private DPoP key. This neutralises a common class of incidents — tokens captured via stack traces, error reports, network proxies, or misconfigured logging. DPoP does NOT defend against full credential-store theft. If an attacker exfiltrates both the private DPoP key AND a live access token from your infrastructure, they can forge proofs and act as you for up to one token TTL. The mitigations are short token TTLs (1 hour in production), key rotation discipline, and reducing blast radius via the credential’s revoke endpoint. Token TTL is the revocation mechanism. If you suspect a credential is compromised, rotate theclient_secret (the rotate endpoint issues a new one) and revoke the client. Outstanding tokens will continue to verify until their exp — at most 1 hour in production. For emergency revocation of in-flight tokens, contact support.
Anton’s signing key rotates every 90 days with a 24-hour publication overlap. The JWKS endpoint at /v1/.well-known/jwks.json always reflects the currently-trusted set; cache it for ≤5 minutes (the response includes a matching Cache-Control).
SDKs
SDKs are not part of v1. Programmatic clients integrate against the raw HTTP surface; the curl example above is the canonical reference. Official SDKs for Go, Node, and Python are tracked as a follow-up initiative — when they ship, the canonical authentication examples will move into the per-language quickstarts.Requirements
- Use HTTPS. Anton only accepts TLS 1.2+ connections. Plaintext requests are dropped at the edge.
- Never commit credentials to source control. Use environment variables or a dedicated secrets manager. The DPoP private key especially — it’s the second half of your bearer-token defense.
- Never include credentials in frontend code. All API calls must originate from a trusted backend.
- Prefer one credential per service. Narrower blast radius when a credential needs to be rotated.
- Wall clock within 60 seconds of UTC. NTP in your container/host. DPoP
iatclaims are time-bounded.