Skip to content

Preview. The API is shared with design partners and may change before launch. Register interest for sandbox access.

OAuth 2.0 and mTLS

Bank-grade integrations authenticate with the OAuth 2.0 client credentials grant. There are no shared secrets: your client proves its identity with a private key that never leaves your infrastructure, ideally in an HSM or a cloud KMS.

Purpose URL
Token endpoint https://partner-api.getphew.com/oauth2/token
Token endpoint (mTLS) https://partner-api-mtls.getphew.com/oauth2/token
Checkout API and Partner API (mTLS) https://api-mtls.getphew.com/v1, https://partner-api-mtls.getphew.com/v1
Authorization server metadata (RFC 8414) https://partner-api.getphew.com/.well-known/oauth-authorization-server
Phew signing keys (JWKS) https://partner-api.getphew.com/.well-known/jwks.json
  1. Choose a client authentication method: private_key_jwt or tls_client_auth.
  2. Send us your public keys, either as a JWKS URL that we fetch (recommended, so you can rotate on your own schedule) or as uploaded public keys. Accepted algorithms: PS256, ES256 and EdDSA. RSA keys must be at least 2048 bits.
  3. For mTLS, send the subject DN of your client certificate and the issuing CA chain. We accept certificates from your own private CA or a public CA.
  4. Tell us the scopes each client needs and your egress IP ranges.
  5. We return a client_id per environment.

Create a client assertion JWT signed with your private key:

// Header
{ "alg": "PS256", "kid": "psp-2026-10", "typ": "JWT" }
// Claims
{
"iss": "cli_01JD8A3B5C7D9E1F3G5H7J9K1M",
"sub": "cli_01JD8A3B5C7D9E1F3G5H7J9K1M",
"aud": "https://partner-api.getphew.com/oauth2/token",
"jti": "5b4f3c1e-8d2a-4e6b-9f0a-1c2d3e4f5a6b",
"iat": 1761220329,
"exp": 1761220389
}

The assertion must expire within 60 seconds of iat, and each jti is accepted only once. Exchange it for an access token:

Terminal window
curl https://partner-api.getphew.com/oauth2/token \
-d grant_type=client_credentials \
-d client_id=cli_01JD8A3B5C7D9E1F3G5H7J9K1M \
-d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
-d client_assertion=eyJhbGciOiJQUzI1NiIsImtpZCI6InBzcC0yMDI2LTEwIn0... \
-d scope="offers:write policies:write"

The response:

{
"access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6InBoZXctMjAyNi0xMCJ9...",
"token_type": "Bearer",
"expires_in": 600,
"scope": "offers:write policies:write"
}

Access tokens are JWTs signed by Phew with ES256. Treat them as opaque; their format may change. Properties you can rely on:

  • They expire after 10 minutes. Cache the token and request a new one about a minute before expiry. Refresh tokens are not issued.
  • They carry only the scopes requested, which must be a subset of the scopes the client is registered for.
  • With mTLS, they are bound to your certificate (RFC 8705 cnf.x5t#S256). Phew rejects the token if it’s presented without the matching certificate.
  • JWKS URL: publish the new key alongside the old one, start signing with it, then remove the old key. We refresh your JWKS every 15 minutes and immediately when we see an unknown kid.
  • Uploaded keys and certificates: send the new key or certificate; both are valid until you confirm the switch.
  • Phew notifies your security contact at least 30 days before any certificate you depend on expires.

Token endpoint errors follow RFC 6749:

error Meaning
invalid_client Assertion or certificate failed verification, unknown client_id, or reused jti
invalid_scope A requested scope isn’t granted to this client
unauthorized_client The client isn’t allowed to use this grant or authentication method
invalid_request Missing or malformed parameter