Skip to main content
POST
Get an access token
Call it from your server: the request carries your Client Secret, which does not belong in a browser or an app people download. Send the secret in the body, or the Client ID and Secret as HTTP Basic credentials in Authorization. The code works once, for 10 minutes: the exchange spends it. Run the same request twice and the second answers 400 invalid_grant. A wrong secret and an unknown Client ID both answer 401 invalid_client, so the answer does not say which one is wrong. A client that registered itself with token_endpoint_auth_method: none sends no secret. It sends the PKCE code_verifier and the redirect_uri it used on the consent URL instead. Send the token on /public/v1 as Authorization: pos_..., with no prefix, even though token_type says bearer. When it stops working is on OAuth apps.

Body

application/json
grant_type
enum<string>
required

Must be authorization_code

Available options:
authorization_code
code
string
required

The authorization code from your callback URL

client_id
string

Your app's Client ID. Leave it out when you send it in a Basic Authorization header

client_secret
string

Your app's Client Secret (starts with pcs_). Leave it out with Basic auth, or for a public PKCE client

code_verifier
string

The PKCE verifier, required when the authorization request carried a code_challenge

redirect_uri
string

Required when the authorization request carried one, and must match it

Response

The access token

id
string

The workspace the person approved your app for

cus
string | null

The workspace's billing customer id, or null

access_token
string

The token to send in the Authorization header (starts with pos_)

token_type
string

Always bearer. On /public/v1 send the token with no prefix all the same

scope
string

Granted scopes: mcp:read mcp:write, plus openid email for clients allowed email claims

Last modified on September 23, 2026