Authentication & Tokens
The API gateway issues HS256 JWTs. Every call (except login) requires a bearer token in the Authorization header.
How it works
The api gateway validates credentials and mints a signed JWT (HS256). Each incoming request is verified against the JWT signature and a server-side session store — so logout is instant and revocation is real.
Tokens are accepted in two ways:
Authorization: Bearer <token>— standard header (preferred)?token=<token>— query parameter (for webhooks / download links)
POST /sessions — Login flows
All flows use POST /sessions. The type field selects the authentication mechanism:
| type | Required fields | Use case |
|---|---|---|
email | email, password | Standard login |
phone | phone, otp | Phone OTP (after POST /sessions/request) |
link | token | Magic link (after POST /sessions/request) |
token | token | Pre-issued one-time token |
external | externalEntity, externalApp | External partner SSO |
Example — email login
curl -X POST https://api.staging.contabeleza.com.br/sessions \
-H "Content-Type: application/json" \
-d '{"type":"email","email":"you@example.com","password":"secret"}'
Successful login response
On success the gateway returns a JSON object (not JSON:API) with the token and enriched session data:
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9…",
"token-type": "user",
"account": {
"id": "3",
"type": "personal",
"email": "you@example.com"
},
"businesses": [
{
"id": "900001",
"brand": "contabeleza",
"permissions": ["invoices:read", "invoices:write"]
}
]
}
}
Store data.token and pass data.businesses[0].id as the ilm-business header on subsequent calls.
JWT claims reference
| Claim | Type | Description |
|---|---|---|
accountId | string | The authenticated account id |
type | string | user | admin | token | external-app |
restrictedTo | string | Business id scope |
jti | string | Unique token id — stored in the server-side session store; revoked on logout |
iat | timestamp | Issued-at (Unix seconds) |
exp | timestamp | Expiry (Unix seconds) |
Token refresh
Call POST /sessions/token-refresh before exp to get a fresh token without re-authenticating:
curl -X POST https://api.staging.contabeleza.com.br/sessions/token-refresh \ -H "Authorization: Bearer $TOKEN"
Returns a new data.token. The old token is revoked immediately.
Forgot password flow
Three-step sequence — no auth required:
- Request reset —
POST /sessions/password/forgotwith{"email":"…"} - Validate token —
POST /sessions/password/validate-tokenwith{"reset-token":"…"} - Set new password —
POST /sessions/password/resetwith{"reset-token":"…","password":"…"}
API key exchange
For machine-to-machine integrations use an API key. The gateway exchanges it for a short-lived external-app JWT:
curl -X POST https://api.staging.contabeleza.com.br/sessions/api \ -H "Authorization: ApiKey your-api-key-here"
Manage API keys at GET/POST /external-app-tokens.
Logout
DELETE /sessions removes the token's JTI from the server-side session store immediately. Any in-flight requests using the same token after this call will receive 401 Unauthorized.
curl -X DELETE https://api.staging.contabeleza.com.br/sessions \ -H "Authorization: Bearer $TOKEN"
Using the token
Swagger UI — open /docs, click Authorize, paste the token (without the Bearer prefix).
curl:
TOKEN=eyJhbGciOi... curl https://api.staging.contabeleza.com.br/accounts/me \ -H "Authorization: Bearer $TOKEN" \ -H "ilm-business: 900001"