Authentication
Key format, scope, the company a key is bound to, rotation.
Every request to /api/v1 authenticates with an API key, sent as a bearer
token. An admin or a bookkeeper of the company mints it in the company's settings,
under Developers (/workspace/settings/company/developers).
Authorization: Bearer tba_…The header is the only credential the API reads. A session cookie is never read.
Key format
A key is tba_ followed by 32 URL-safe characters. There is no environment
segment, because there is no sandbox to tell apart.
The raw key is shown once, when it is minted. Tabba stores only its SHA-256 hash, and the Developers page shows a key by its prefix and its last four characters. A lost key cannot be recovered: revoke it and mint a new one.
Scope
A key is minted with one of two scopes:
read: everyGETendpoint. For dashboards and a one-way sync out of Tabba.read_write: everything areadkey does, and everyPOST,PUT,PATCHandDELETE.
A read key on a write endpoint is refused:
HTTP/1.1 403 Forbidden
{
"error": {
"type": "permission_error",
"code": "SCOPE_INSUFFICIENT",
"message": "This endpoint needs a read_write key; this key is read.",
"request_id": "req_…"
}
}The refusal comes before the rate limit is counted, so it spends nothing of the key's budget.
One key, one company
A key is bound to one connected company when it is minted, and it can be
minted only for a company that is connected. No URL and no body of the API
names a company: the key does. GET /config answers which one, as
integration_id and company_name.
A record of any other company does not exist as far as the request can tell:
a path that names one is answered 404 with NOT_FOUND.
If you operate several companies, mint one key for each and route requests in your client.
Disconnecting a company revokes its keys. A revocation is final, so after the company is connected again an admin or a bookkeeper mints a new key.
Refused keys
| Request | Status | Code |
|---|---|---|
No Authorization: Bearer header | 401 | UNAUTHORIZED |
| A key that is malformed, unknown or revoked | 401 | INVALID_API_KEY |
A revoked key and an unknown key are answered alike. Revocation takes effect at once: the next request under the key is refused.
Requests that carry no key of Tabba's are counted per client address and are
answered 429 with RATE_LIMITED past their limit. A request under your live
key is not counted there. See Errors.
Rotation
To rotate a key with no downtime:
- Mint a new key for the same company beside the current one. A company can have several live keys.
- Deploy your integration with the new key.
- Check on the Developers page that the new key's last use is advancing.
- Revoke the old key.
What the API does not do
These stay in the workspace, where an admin does them from a signed-in session:
- Inviting and removing people, and changing a person's role.
- Connecting and disconnecting an accounting system.
- Minting and revoking API keys.
- Registering a webhook endpoint, rotating its signing secret and replaying a delivery.
Keep the key on a server
The key acts for the whole company within its scope. The API sends no CORS header: it is called by servers. Do not embed a key in a frontend bundle or send it from a browser.
Every call under a key is written to the account's activity log with the key
and the request_id of the call. A registration of work is credited to the
person the request names, since a key is not a person.