Blue Reacher
OAuth endpoints16 / 46

OAuth endpoints

OAuth 2.0 authorization code flow with stateless JWT access + refresh tokens.

OAuth 2.0 authorization code flow with stateless JWT access + refresh tokens.

Every route takes Authorization: Bearer <ACCESS_TOKEN> unless the auth line says otherwise. Ids are numbers. Errors use the shape on the errors page.

RouteScopeWhat it does
GET /integrations/install/{client_id}noneStart the OAuth authorization code flow.
POST /v1/oauth/tokennoneExchange an authorization code for an access token and refresh token.
POST /v1/oauth/tokennoneUse the refresh token to obtain a new access token.

Send the user to the install URL

GET https://app.bluereacher.com/integrations/install/{client_id}?redirect_uri={redirect_uri}&state={state}

Auth: none. The user's browser opens this URL.

Start the OAuth authorization code flow.

This is a dashboard URL (https://app.bluereacher.com), not an API-host endpoint — you redirect the user's browser here. They see a consent page listing the scopes your app requests. If they are not logged in, Blue Reacher redirects them to the login page first and returns them here after sign-in. When they click Install, the browser is redirected to your redirect_uri with a single-use ?code= query parameter, plus state echoed verbatim when you sent one. If they click Cancel, the browser is redirected to your redirect_uri with ?error=access_denied (and the same state) and no code is issued.

Parameters

NameInTypeRequiredDescription
client_idpathstringyesThe public client_id of your app (issued when your app is registered).
redirect_uriquerystringyesWhere Blue Reacher should send the user after consent. Must match the redirect_uri registered on the app.
statequerystringnoOpaque value generated by your app (CSRF token). It is not interpreted by Blue Reacher and is returned unchanged, URL-encoded, as state on both the success and the cancel redirect. Verify it on your callback before exchanging the code.

Request

Browser redirect
https://app.bluereacher.com/integrations/install/<CLIENT_ID>?redirect_uri=<YOUR_CALLBACK>&state=<RANDOM>

Responses

A 302 reply (On Install: redirect to your redirect_uri with ?code=<32-char hex> (and your state)):

{
  "Location": "https://your-app.com/oauth/callback?code=4f8a7e1d2c9b3a5f6e0d1c2b7a8f9e6d&state=xyz123"
}
StatusWhenMessage
302On Install: redirect to your redirect_uri with ?code=<32-char hex> (and your state)
302On Cancel: redirect to your redirect_uri with error=access_denied (and your state); no code is issued

Exchange code for tokens

POST https://api.bluereacher.com/v1/oauth/token

Auth: client_id and client_secret in the JSON body. No Bearer token.

Exchange an authorization code for an access token and refresh token.

Server-to-server. Send the code your callback received along with your client_id + client_secret. Returns both tokens — store them in your database, keyed by the installing user. Codes are single-use and expire 10 minutes after consent: a second exchange with the same code returns an error indicating that the code has already been used. If the exchange times out or returns a 5xx, retry it once; if the retry reports the code as already used, the first attempt was processed and no tokens can be recovered — send the user through the install URL again. The token endpoints are not covered by the per-installation API rate limits and do not return 429.

Request

curl -X POST "https://api.bluereacher.com/v1/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
  "grant_type": "authorization_code",
  "code": "4f8a7e1d2c9b3a5f6e0d1c2b7a8f9e6d",
  "client_id": "<YOUR CLIENT_ID>",
  "client_secret": "<YOUR CLIENT_SECRET>",
  "redirect_uri": "https://your-app.com/oauth/callback"
}'

Responses

A 200 reply (Success — tokens issued):

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 86400,
    "scopes": [
      "contacts.read",
      "contacts.write"
    ]
  }
}
StatusWhenMessage
200Success — tokens issued
400Invalid or expired authorization codeInvalid or expired authorization code
400Code already used (single-use enforcement)Authorization code has already been used. Re-start the install to get a fresh code.

Refresh tokens

POST https://api.bluereacher.com/v1/oauth/token

Auth: client_id and client_secret in the JSON body. No Bearer token.

Use the refresh token to obtain a new access token.

When you get a 401 from the API ("Invalid or expired access token"), call this endpoint with your stored refresh_token to get a fresh pair. Replace both stored tokens with the new values. Access tokens expire after 24 hours (expires_in); refresh tokens after 1 year. Every refresh returns a new refresh token, but tokens are stateless signed JWTs: the previous refresh token is NOT invalidated by rotation and stays usable until its own expiry or until the installation is suspended. Keep only the newest pair. Because the old token stays valid, a refresh that times out or returns a 5xx is safe to retry with exponential backoff (for example 1 s, 2 s, 4 s). The token endpoints are not covered by the per-installation API rate limits and do not return 429.

Request

curl -X POST "https://api.bluereacher.com/v1/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
  "grant_type": "refresh_token",
  "refresh_token": "<YOUR_REFRESH_TOKEN>",
  "client_id": "<YOUR CLIENT_ID>",
  "client_secret": "<YOUR CLIENT_SECRET>"
}'

Responses

A 200 reply (Fresh tokens issued):

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "Bearer",
    "expires_in": 86400,
    "scopes": [
      "contacts.read",
      "contacts.write"
    ]
  }
}
StatusWhenMessage
200Fresh tokens issued
401Refresh token invalid or revokedInvalid or expired refresh_token

On this page