Skip to main content

Authentication and keys

Every call carries a key of the company in the Authorization header:

GET /api/v1/reports/summary/?date_from=2026-10-01&date_to=2026-10-31 HTTP/1.1
Host: app.kabal-attendance.com
Authorization: Bearer kba_4Hq0x9mT1vZp8bLwYc3RkN7sJ2dF6gAeU5oXiQyKtMh

There are no cookies, sessions or tokens to refresh: the key is the whole credential, and it works until it expires or someone revokes it.

The key belongs to the company​

A key is not tied to the person who created it. It reads every employee of every site of the company, and it keeps working if that person leaves the company or loses access to the app. That is why only an administrator who sees the whole company can create or revoke one: a user limited to some sites sees the list of keys and nothing else.

What a key can do is fixed: read the summary and the detail. It cannot write anything, read photos, or call any other route of the app; a key sent to another route is refused with a 401.

Create, expire, revoke​

Keys are managed in the app, under API:

  • Create. A name and an expiry: 30, 90 or 365 days, a date of your choice, or no expiry. A key that expires on a date works that whole day, in the company's timezone. The key is shown once.
  • The list shows each key's name, its first characters (kba_a1b2c3d4…, to recognise it), its state (active, expired, revoked), who created it and when, its expiry and when it was last used. The last use is updated at most once a minute.
  • Revoke. Stops the key at once. A revoked key stays in the list as a record and cannot be brought back; create a new one instead.

Each plan sets how many live keys a company can have. Expired and revoked keys do not count.

To rotate a key without a gap, create the new one, deploy it in your system, check a call with it, and then revoke the old one.

When a key is refused​

The answer is always a JSON envelope with a stable code for your program and a detail in Spanish for a person:

{ "detail": "La llave del API venció.", "code": "api_key_expired" }
StatuscodeWhat happenedWhat to do
401not_authenticatedNo key was sent, or it was not sent as Authorization: Bearer.Send the header.
401api_key_invalidThe key does not exist or was revoked. The two are answered the same on purpose.Ask the administrator for a new key.
401api_key_expiredThe key passed its expiry date.Ask the administrator for a new key.
401company_suspendedThe company is suspended or was closed. Nothing about the key changed.Talk to the company's administrator.
403api_not_includedThe company's plan has no API. The key comes back to life by itself if the plan includes it again.The administrator changes the plan.

Every 401 carries WWW-Authenticate: Bearer realm="integration".

A company whose paid subscription expired keeps reading: the API answers as usual while the app is read-only.

Invalid keys from one address​

Kabal counts the refused keys that arrive from each IP address. After 30 in a minute, every call from that address gets a 429 throttled until the minute is over, including calls with a good key: do not retry a 401 in a loop. See Limits.

Keep the key secret​

  • Store it in your secret manager or in an environment variable, never in a repository or a URL.
  • Send it only to https://app.kabal-attendance.com. Kabal never asks for it by email, chat or phone.
  • If it may have leaked, revoke it in the app and create another.