Refresh and revoke tokens
How long each token lives, how rotation works, and every way a token can die.
Lifetimes
| Thing | Lives | Reusable |
|---|---|---|
| Authorization code | 10 minutes | No — single use |
| Access token | 1 hour (`expires_in: 3600`) | Until it expires |
| Refresh token | 90 days | Once — it rotates on every use |
Refreshing
curl -X POST https://api.trabalance.com/oauth/token \
-H "Content-Type: application/json" \
-d '{ "grant_type": "refresh_token", "refresh_token": "…",
"client_id": "tc_…", "client_secret": "…" }'You get a new access token and a new refresh token; store both and discard the old pair. The response also carries scope — the same scopes the grant was issued with, as a space-separated feature_code:verb list.
A refresh past the 90-day window answers 401 invalid_grant. There is no recovery from your side: send the user through the authorization flow again.
Revoking
curl -X POST https://api.trabalance.com/oauth/revoke \
-H "Content-Type: application/json" \
-d '{ "token": "…", "token_type_hint": "access_token" }'Either kind of token is accepted. From the developer portal you can also revoke a single business's token, or every token the app holds, from the Tokens tab.
Every way a token dies
| Cause | Effect | What the caller sees |
|---|---|---|
| It expired | Access token past its hour | `401 invalid_token` |
| You revoked it | From /oauth/revoke or the Tokens tab | `401 invalid_token` |
| You regenerated the client secret | Live access tokens keep working until they expire; refreshing needs the new secret | `401 invalid_grant` on refresh |
| You deactivated the app | Nothing authorises against it any more | `invalid_client` at authorisation |
| The user lost the right | The bound user no longer holds the feature, or the subscription lapsed | `403 insufficient_permissions` |
Because refresh tokens rotate, two processes refreshing the same token race: the loser holds a token that is already spent. Refresh in one place and share the result.