Authentication
The API uses the OAuth 2.0 client credentials grant
(RFC 6749 section 4.4).
Your integration exchanges a client_id and client_secret for a short-lived
access token, then sends that token on every request.
Get a token
Section titled “Get a token”POST /oauth/token with grant_type=client_credentials. Send the credentials
with HTTP Basic (recommended) or in the form body.
curl -X POST https://api.uniqueonthego.com/oauth/token \ -u "$UNIQUE_CLIENT_ID:$UNIQUE_CLIENT_SECRET" \ -d grant_type=client_credentials{ "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDkifQ...", "token_type": "Bearer", "expires_in": 3600, "scope": "tasks:read locations:read"}Use the token
Section titled “Use the token”Send it in the Authorization header:
GET /v1/tasks?from=2026-09-26T00:00:00Z&to=2026-09-27T00:00:00Z HTTP/1.1Host: api.uniqueonthego.comAuthorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjIwMjYtMDkifQ...Tokens are never accepted as query parameters.
Scopes
Section titled “Scopes”| Scope | Grants |
|---|---|
tasks:read |
GET /v1/tasks and GET /v1/tasks/{id} |
locations:read |
GET /v1/locations |
By default a token receives every scope granted to the client. Pass
scope=tasks:read to request a narrower token.
Token lifetime and caching
Section titled “Token lifetime and caching”- Tokens are valid for
expires_inseconds (one hour). - Cache the token and reuse it for every request until it is about to expire. Refresh it about five minutes early to avoid races.
- The token endpoint has its own, lower rate limit. Requesting a token per API call will get you throttled. See Rate limits.
- There are no refresh tokens. When a token expires, request a new one with your credentials.
let cached = null;
async function getToken() { if (cached && Date.now() < cached.expiresAt - 5 * 60 * 1000) { return cached.token; } const response = await fetch("https://api.uniqueonthego.com/oauth/token", { method: "POST", headers: { Authorization: "Basic " + btoa(`${process.env.UNIQUE_CLIENT_ID}:${process.env.UNIQUE_CLIENT_SECRET}`), "Content-Type": "application/x-www-form-urlencoded", }, body: "grant_type=client_credentials", }); if (!response.ok) throw new Error(`Token request failed: ${response.status}`); const body = await response.json(); cached = { token: body.access_token, expiresAt: Date.now() + body.expires_in * 1000 }; return cached.token;}Errors
Section titled “Errors”The token endpoint follows the OAuth error format from RFC 6749 section 5.2:
| Status | error |
Meaning |
|---|---|---|
| 400 | invalid_request |
A required parameter is missing or duplicated. |
| 400 | unsupported_grant_type |
Only client_credentials is supported. |
| 400 | invalid_scope |
The requested scope is not granted to this client. |
| 401 | invalid_client |
Wrong, revoked or expired credentials. |
Every other endpoint uses the standard error format. A
missing or expired token returns 401 unauthorized; a token without the
required scope returns 403 forbidden.