OAuth
OAuth is the path for a third-party application that connects to a customer’s Infinite Audience account on their behalf — Zapier today. It’s not a self-service “register your own OAuth app” flow: the set of client applications is a fixed, platform-approved registry, each with its own allowed scopes and redirect URIs. If you’re integrating your own backend or scripts against your own account, use an API key instead — it’s simpler and doesn’t require a registered client.
The flow
Section titled “The flow”Standard OAuth 2.0 authorization code grant with mandatory PKCE (S256) — this is RFC 9700’s recommendation, not optional here:
- Your app redirects the user to
GET /v1/oauth/authorizewithclient_id,redirect_uri,response_type=code,scope,code_challenge, andcode_challenge_method=S256. - The user reviews and approves a consent screen showing exactly which scopes your app is requesting.
- We redirect back to your
redirect_uriwith a short-lived authorizationcode. - Your backend exchanges that code — plus the original
code_verifier— atPOST /v1/oauth/tokenfor an access token and a refresh token. - Use the access token as a normal bearer token. When it expires, use the refresh token to get a new one without involving the user again.
GET /v1/oauth/authorize
Section titled “GET /v1/oauth/authorize”| Parameter | Required | Notes |
|---|---|---|
client_id |
yes | Must resolve to a registered client, or this 400s directly (there’s no redirect target to trust yet). |
redirect_uri |
yes | Must be on that client’s registered allow-list. |
response_type |
yes | Must be code — nothing else is supported. |
scope |
no | Space-separated. Anything not on the client’s allowed-scope list is rejected. |
code_challenge |
yes | RFC 7636 PKCE challenge. |
code_challenge_method |
yes | Must be S256 — plain is rejected. |
state |
recommended | Echoed back on both success and error redirects. |
Every failure after client_id/redirect_uri validation redirects back to your app with
error and error_description query params (RFC 6749 §4.1.2.1) rather than showing an error
page — validate client_id and redirect_uri yourself before sending users here if you want
to fail fast.
POST /v1/oauth/token
Section titled “POST /v1/oauth/token”Two grant types:
# Exchanging an authorization codecurl -X POST https://api.infiniteaudience.ai/v1/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=$AUTH_CODE" \ -d "redirect_uri=$REDIRECT_URI" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRET" \ -d "code_verifier=$CODE_VERIFIER"
# Refreshing an expired access tokencurl -X POST https://api.infiniteaudience.ai/v1/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "refresh_token=$REFRESH_TOKEN" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRET"{ "access_token": "cfo_eyJhbGciOi...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "...", "scope": "discovery purchase"}Refresh tokens last 90 days. An authorization code is valid for 60 seconds and single- use — replaying it revokes the whole grant as a security response, not just a “try again.”
Revoking access
Section titled “Revoking access”POST /v1/oauth/revoke (client-authenticated, RFC 7009) revokes a specific token. A user can
also revoke your app’s entire grant from their own account settings at any time — build your
integration to handle a sudden 401 on a previously-working refresh token gracefully.