Skip to main content
S2S authentication is a two-step process: exchange your credentials for a JWT, then attach that JWT as a Bearer token on every subsequent request.
Your api_key and api_secret are shown once when the Yonne admin generates them. Store them securely in environment variables immediately — they cannot be retrieved again (only regenerated via rotate).

Step 1 — Exchange credentials for a JWT

POST /api/courier/s2s/auth/token
curl --request POST "https://api.yonne.app/api/courier/s2s/auth/token" \
  --header "Content-Type: application/json" \
  --data '{
    "api_key": "ck_live_xxxxxxxxxxxx",
    "api_secret": "sk_live_xxxxxxxxxxxx"
  }'
Success response:
{
  "token": "<jwt>",
  "courier_id": 123,
  "courier_name": "Acme Logistics",
  "expires_in": 86400
}
FieldDescription
tokenThe JWT to attach to all S2S requests
courier_idYour courier ID on the platform
expires_inSeconds until the token expires — always 86400 (24 hours)

Step 2 — Attach the JWT to every request

All protected S2S endpoints require the token in the Authorization header:
Authorization: Bearer <token>
curl --request GET "https://api.yonne.app/api/courier/s2s/metrics/summary" \
  --header "Authorization: Bearer <token>"

Token lifetime and refresh

The JWT is valid for 24 hours. Implement a simple refresh strategy in your integration:
Node.js
let token = null;
let tokenExpiry = null;

async function getToken() {
  if (token && Date.now() < tokenExpiry - 60_000) {
    return token; // reuse while still valid (with 1-min buffer)
  }

  const res = await fetch("https://api.yonne.app/api/courier/s2s/auth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      api_key: process.env.COURIER_API_KEY,
      api_secret: process.env.COURIER_API_SECRET
    })
  });

  const data = await res.json();
  token = data.token;
  tokenExpiry = Date.now() + data.expires_in * 1000;
  return token;
}

Credential prefixes

PrefixCredential
ck_live_api_key
sk_live_api_secret

Authentication errors

CodeHTTPMeaningFix
TOKEN_MISSING401No Authorization headerAdd Authorization: Bearer <token> to your request
TOKEN_EXPIRED401Token is older than 24 hoursRe-authenticate to get a fresh token
TOKEN_INVALID401Bad signature or wrong token typeEnsure you’re using a token from /api/courier/s2s/auth/token
COURIER_NOT_FOUND404The courier_id in the token no longer existsContact Yonne support
S2S_DISABLED403Integration has been disabled by adminContact your Yonne account manager
DB_ERROR503Platform database unreachableRetry with exponential backoff
A 403 S2S_DISABLED response means your integration was turned off on the admin side. Your credentials are still intact — the Yonne admin just needs to re-enable the integration via toggle.