Authentication
The OneFinOps API uses OAuth 2.0 client credentials. You exchange a client id and secret for a short-lived bearer token, then pass that token on every API call.
Issue an OAuth client
OAuth clients are managed from the Developer hub in your OneFinOps dashboard.
- The Live tab issues production clients with id prefix
ofin_live_*. - The Sandbox tab issues sandbox clients with id prefix
ofin_test_*.
When you create a client we return the client_id (visible forever) and client_secret (shown once). Store the secret in a secrets manager — we cannot recover it; if you lose it, rotate.
The scope onefinops.api is attached automatically. You don't pick per-action scopes and you don't pass scope=... on the token request.
Token endpoint
Production and sandbox share the same Keycloak realm. The token endpoint is the same for both environments:
https://login.onefinops.com/realms/onefinops/protocol/openid-connect/token
Which environment the token runs against is decided by the API host you call:
| Environment | API host | Client prefix |
|---|---|---|
| Production | https://api.in.onefinops.com | ofin_live_* |
| Sandbox | https://sandbox-api.in.onefinops.com | ofin_test_* |
Request a token
curl -X POST 'https://login.onefinops.com/realms/onefinops/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d 'client_id=ofin_test_<your-client-id>' \
-d 'client_secret=<your-client-secret>'Response:
{
"access_token": "eyJhbGciOi...",
"expires_in": 900,
"token_type": "Bearer",
"scope": "onefinops.api"
}The token is a JWT — your code doesn't need to parse it, but it does carry:
aud:onefinops.api(the API audience)organization_id: pins the token to your tenant; you cannot override this in the request body or path.exp: token expiry (15 minutes from issue).
Pass the token on every call as Authorization: Bearer <access_token>.
Token lifetime + caching
Tokens are valid for 15 minutes. Cache them — the token endpoint is rate-limited and minting one per request will eventually return 429.
A simple cache rule: mint a new token when the current one has < 60 seconds left. Most OAuth client libraries handle this automatically.
Permissions
Per-action OAuth scopes (einvoice:generate etc.) do not exist on this API. What your token can do is governed by:
- Your plan / entitlement. If your plan includes only e-invoicing, a call to
/v1/ewaybills/*will authenticate successfully but be rejected at the entitlement layer. - Per-client rate limits. Applied per OAuth client per minute, regardless of which endpoint is hit. See Rate limits.
We chose this over per-scope authorization deliberately: you don't have to maintain a scope catalogue in client config, and we can enable or disable capabilities on your account without forcing you to rotate keys.
Rotating secrets
Rotate a client's secret from the Developer hub at any time. Rotation issues a new secret and starts a 24-hour overlap window during which both the old and new secrets work — long enough to roll your deployment without downtime. After 24 hours, the old secret is revoked.
Common mistakes
- Using the token endpoint as the API base URL. The token endpoint is on
login.onefinops.com; the API itself is onapi.in.onefinops.com(production) orsandbox-api.in.onefinops.com(sandbox). - Calling sandbox endpoints with a production client. Use the
ofin_test_*client for sandbox and theofin_live_*client for production. Mixing them returns 401 because the client's allowed audience doesn't match the API host. - Embedding the client secret in browser or mobile code. Client credentials is a server-to-server flow. A secret shipped to a public client can be extracted.
- Minting a token per request. Cache and reuse. The token endpoint will rate-limit aggressive churn.
- Sending
scope=einvoice:generateor similar. No per-action scopes exist. Omit thescopeparameter entirely.
Where to next
- Quickstart — mint a token and register your first IRN.
- Sandbox vs production — environment differences and test GSTINs.
- Rate limits — per-client request budgets.
- Errors — what to do when auth fails.
