Authentication
The API uses the OAuth2 client-credentials grant. You exchange a client ID and secret for a short-lived bearer token, then send that token on every request.
We issue you a client ID and client secret out of band when you're onboarded — there's no self-serve signup. Treat the secret like a password: store it somewhere secret, never commit it, never put it in a mobile app or front-end. If you're issued both a live and a test credential, they're completely separate keys.
Exchange your credentials at POST /oauth/token with grant_type=client_credentials. The body can be form-encoded or JSON.
curl https://api.elderella.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=client_credentials \
-d client_id=$ELDERELLA_CLIENT_ID \
-d client_secret=$ELDERELLA_CLIENT_SECRET
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "connections:write files:write"
}
Send it as a bearer token in the Authorization header on every /v1 request.
Authorization: Bearer eyJhbGciOi...
Tokens are short-lived — the exact lifetime is in the expires_in field (seconds) of the token response. Request a fresh token when the current one is close to expiring rather than caching it indefinitely. There's no refresh token; you re-run the client-credentials exchange, which is cheap. A request with an expired, malformed, or revoked token returns 401.
Ring 1 has one scope per resource:
| Scope | Grants |
|---|---|
connections:write | Request, poll, and sever connections (/v1/connections). |
files:write | Send files and poll their status (/v1/files). |
Ask for a subset with the optional scope parameter (space-separated) on the token request, or omit it to be granted everything your partner account is allowed. A valid token that lacks the scope a route needs returns 403 insufficient_scope. Read scopes don't exist yet — they arrive with a later ring of the API.
To rotate your secret, contact us at hello@elderella.com and we'll issue a new one. Roll it in by switching the secret your token exchange uses; existing tokens keep working until they expire. If a secret is ever exposed, tell us and we'll revoke it — a revoked credential immediately stops minting tokens.
Every credential failure at the token endpoint — an unknown client_id, a wrong secret, a revoked credential, a suspended partner — returns the same invalid_client error, in both the response body and its timing. There's no way to use the token endpoint to learn whether a given client ID exists. Don't branch on the specific reason; there isn't one.
{ "error": "invalid_client" }
The token endpoint is rate limited per client IP as a brute-force backstop. Exceed it and you get 429 with a Retry-After header (seconds). Back off for that long and retry. See error handling for the shape of the response.