Authentication
The Treedis API uses OAuth2 as its primary authentication method. You exchange a set of client credentials for a short‑lived access token, then send that token as a Bearer token on every request.
A legacy API key (X-API-Key) is also accepted on protected endpoints, but OAuth2 is recommended for all new integrations — it issues short‑lived tokens, supports scoped access, and rotates refresh tokens automatically.
Base URLs
- Production:
https://api.treedis.com - Staging:
https://stage-api.treedis.com
OAuth2 endpoints live under /v1/api/oauth2.
How OAuth2 works here
client_id + client_secret ──▶ POST /v1/api/oauth2/token ──▶ access_token (15 min)
refresh_token (7 days)
access_token ──▶ Authorization: Bearer {access_token} ──▶ any API endpoint
refresh_token ──▶ POST /v1/api/oauth2/token (grant_type=refresh_token) ──▶ new token pair
- Access tokens are JWTs, valid for 15 minutes by default. Send them as
Authorization: Bearer {access_token}. - Refresh tokens are valid for 7 days by default and are rotated on every use — each refresh returns a brand‑new refresh token, and the previous one stops working.
- Up to 10 active sessions are allowed per user.
Step 1 — Get client credentials
Client credentials (a clientId and clientSecret) are provisioned by Treedis for your integration — they aren't self‑service. Ask your Treedis contact to issue them; you'll receive a pair like:
{
"clientId": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"clientSecret": "1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7a8b9c0d1e2f3g4"
}
The clientSecret is shown only once and is stored hashed — it cannot be retrieved later. Store it securely. If it's lost, ask Treedis to reissue your credentials.
Step 2 — Exchange credentials for an access token
Call the token endpoint with the password grant type. You can pass the credentials in the JSON body, or as an RFC 6749 Basic Auth header.
Option A — credentials in the body
curl -X POST "https://api.treedis.com/v1/api/oauth2/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "password",
"client_id": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
"client_secret": "1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z7a8b9c0d1e2f3g4"
}'
Option B — HTTP Basic Auth header
Base64‑encode client_id:client_secret and send it as a Basic credential. When present, the header takes precedence over body credentials.
curl -X POST "https://api.treedis.com/v1/api/oauth2/token" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $(printf '%s' 'a1b2c3d4...:1a2b3c4d...' | base64)" \
-d '{ "grant_type": "password" }'
A successful response returns the token pair:
{
"status": 200,
"message": "Success",
"timestamp": 1716146262053,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "api"
}
}
Step 3 — Call the API with your access token
Send the access token in the Authorization header:
curl -X GET "https://api.treedis.com/v1/api/tours" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Step 4 — Refresh the access token
When the access token expires (after ~15 minutes), exchange your latest refresh token for a new pair. Do not reuse an old refresh token.
curl -X POST "https://api.treedis.com/v1/api/oauth2/token" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "refresh_token",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
The response contains a new access_token and a new refresh_token. Replace your stored refresh token with the new one each time.
Token reuse is treated as a breach. If a refresh token is used more than once, the API invalidates all of the user's active sessions as a security measure. Always store and send only the most recent refresh token.
Scopes
Access tokens carry a scope claim that controls which operations they may perform. Request scopes with the optional scope field on the password grant (defaults to ["api"]):
{
"grant_type": "password",
"client_id": "a1b2c3d4...",
"client_secret": "1a2b3c4d...",
"scope": ["read:projects", "write:projects"]
}
| Scope | Grants |
|---|---|
api |
Full API access (default) |
read:tours / write:tours / delete:tours |
Tour read / write / delete |
read:projects / write:projects / delete:projects |
Project read / write / delete |
read:users / write:users |
User read / write |
read:analytics |
Analytics read |
read:workspaces / write:workspaces |
Workspace read / write |
Scope hierarchy: api grants everything; a write:* scope includes its read:*; a delete:* scope includes both read:* and write:*. A request to an endpoint you lack scope for returns 403 with an insufficient_scope error.
Legacy: API key
Protected endpoints also accept a static API key in the X-API-Key header:
curl -X GET "https://api.treedis.com/v1/api/tours" \
-H "X-API-Key: your-api-key-here"
Prefer OAuth2 for new integrations. API keys are long‑lived and unscoped; treat them as secrets and rotate them if exposed.
Rate limiting & errors
The token endpoint is rate limited to 5 attempts per 60 seconds; exceeding it blocks further attempts for 30 minutes (429 Too Many Requests).
Common authentication errors (401/403):
| Message | Meaning |
|---|---|
Client authentication failed |
Wrong client_id / client_secret |
The access token has expired |
Refresh the token |
The refresh token is invalid or expired |
Re‑authenticate with the password grant |
Refresh token has already been used |
Reuse detected — all sessions were revoked; re‑authenticate |
The session has been revoked |
Session ended (logout, credential rotation, or reuse) |
The requested scope is invalid or unknown |
Remove or correct the requested scope |
Maximum number of active sessions exceeded |
Too many sessions (max 10) — let old ones expire |

