Skip to main content

Authentication

The Reeds API uses OAuth 2.0 client credentials. You exchange a client id and secret for an access token, then send that token as a Bearer token on every request.

Get your credentials​

Each account has a client id and a client secret for each mode. Find them in Dashboard → Developers.

CredentialTest modeLive mode
Client idrci_test_...rci_live_...
Client secretrcs_test_...rcs_live_...
  • A secret is shown once. Copy it when you create it. Reeds stores only a hash.
  • Two secrets can be active at the same time, so you can rotate a secret without downtime: create the new one, deploy it, then revoke the old one.
  • Optional, and recommended for live credentials: limit them to your servers' IP addresses with the IP allowlist. It is off by default, and test credentials are never restricted.
Keep secrets on your server

Never put a client secret in a browser, a mobile app or a public repository. Call Reeds from your backend. The prefixes make leaked secrets easy to spot, so revoke any secret that is exposed.

The API Reference's Test Request button and the dashboard's API console accept test credentials only. Live credentials sent from a browser get 400 unauthorized_client from /oauth/token and 403 TEST_MODE_ONLY from the API.

Get an access token​

Send POST https://api.getreeds.co/oauth/token with grant_type=client_credentials, your client id and your client secret. You can send them form-encoded, as JSON, or as HTTP Basic credentials. The endpoint follows the OAuth 2.0 standard, so off-the-shelf OAuth libraries work.

curl https://api.getreeds.co/oauth/token \
-d grant_type=client_credentials \
-d client_id="$REEDS_CLIENT_ID" \
-d client_secret="$REEDS_CLIENT_SECRET"
Response 200
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "shipping",
"livemode": false
}
FieldDescription
access_tokenThe token to send on every API call
token_typeAlways Bearer
expires_inSeconds until the token expires. Tokens last one hour (3600).
scopeThe scopes the token carries. v1 has one scope, shipping.
livemodetrue for live credentials, false for test credentials

Use the token​

Send it in the Authorization header on every call:

Authorization: Bearer <access_token>

Cache and refresh the token​

Don't request a token for every API call. Cache it, and fetch a new one shortly before it expires. The token endpoint allows 60 requests a minute per client, so a token-per-request design will hit the limit.

reeds-token.js
let cached = { token: null, expiresAt: 0 };

export async function getAccessToken() {
// Refresh 60 seconds early so a token never expires mid-request.
if (cached.token && Date.now() < cached.expiresAt - 60_000) {
return cached.token;
}
const res = await fetch('https://api.getreeds.co/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: process.env.REEDS_CLIENT_ID,
client_secret: process.env.REEDS_CLIENT_SECRET,
}),
});
if (!res.ok) throw new Error(`Token request failed: ${res.status}`);
const body = await res.json();
cached = {
token: body.access_token,
expiresAt: Date.now() + body.expires_in * 1000,
};
return cached.token;
}

Authentication errors​

HTTPCodeMeaningWhat to do
401TOKEN_EXPIREDThe token is older than an hourGet a new token and retry the request
401UNAUTHENTICATEDThe token is missing, invalid or revokedCheck the header. If the token was revoked, fix your credentials. Don't loop on this.
400invalid_request or unsupported_grant_typeA field is missing, the credentials were sent both in the body and as HTTP Basic, or grant_type isn't client_credentialsFix the request
400unauthorized_clientA live client id came from a browser, or from an IP address that isn't on your live allowlistCall from your server; check the allowlist
401invalid_clientThe client id or secret sent to /oauth/token is wrong or revoked, or live credentials were used before your account is approvedCheck you are using the matching id and secret for the same mode
403TEST_MODE_ONLYA live token was sent from a browser, or to a sandbox endpointUse test credentials there; call with live credentials only from your server
403INSUFFICIENT_SCOPEThe token doesn't carry the scope the endpoint needsUse credentials for an account that has the scope
503temporarily_unavailableReeds is busy and didn't look at the requestWait the Retry-After seconds, then ask again

The lowercase codes are standard OAuth errors from /oauth/token, such as { "error": "invalid_client" }, not the usual Reeds error format. See Errors for the rest.

You can limit your live credentials to the IP addresses of your own servers. It is optional and off by default, so nothing changes until you set it up. We recommend it: if a secret leaks, it can't be used from anywhere else, because Reeds checks the IP address on the token request and on every API call.

To set it up:

  1. In the dashboard, switch to Live mode and open Developers. The IP allowlist card is under your credentials.
  2. Look at Recent IP addresses. These are the addresses that used your live credentials in the last 30 days. Press Add next to each one that is yours, or type an address or a range yourself.
  3. Adding the first address turns the allowlist on. The dashboard asks you to confirm first, and lists any recent address that would be refused.

What to know:

  • An entry is one IPv4 or IPv6 address, or a range such as 41.58.0.0/16, with an optional label. You can add up to 50.
  • Use the public IP address your servers call Reeds from. Private and reserved addresses (such as 192.168.x.x, 10.x.x.x or 100.64.x.x) are refused, and so are ranges wider than /16 for IPv4 or /48 for IPv6.
  • Once it is on, a live request from any other address is refused. A token request gets 400 unauthorized_client, and an API call with a live token gets 403 IP_NOT_ALLOWED. Neither does anything or costs anything.
  • Every change, adding or removing an address, asks for a 6-digit code from your authenticator app (recovery codes aren't accepted), so a stolen session alone can't open the list. Turn on two-factor authentication in Settings first. The account's Owners are emailed about every change.
  • Changes take effect within a minute. Removing the last address turns the allowlist off again.
  • Test credentials are never restricted, so you can build and test from anywhere.
  • If your servers' addresses change (for example when you move host), add the new ones before you switch over.
  • The allowlist needs fixed outgoing addresses. Serverless functions and some hosting platforms send requests from addresses that change, so their calls would be refused at random. Give them a fixed outgoing IP (most clouds call it a NAT gateway or static egress IP) before you turn the allowlist on, or leave it off.

Revoking a secret​

Revoking a secret in the dashboard also ends every token issued with it, within a minute. Rotate a secret by creating its replacement first, so there is no gap.

Next steps​