Skip to Content
Authentication

Authentication and API keys

The API uses company API keys (service accounts, not tied to a user). Every request is authenticated with the key as a Bearer token:

curl https://api.kinmu.app/v1/organization \ -H "Authorization: Bearer kinmu_sk_live_xxxxxxxx"

Nature of the keys

The company is always resolved from the key: you never send a companyId in the URL or the body.

AspectDetail
Formatkinmu_sk_live_<40+ chars> (production) · kinmu_sk_test_<40+ chars> (sandbox).
VisibilityShown only once when created. Afterwards you only see the prefix + the first few characters.
IssuanceFrom the dashboard my.kinmu.app → Developers (only global_admin / company_manager).
Limit10 active keys per company by default; configurable per company in the addon settings (max_active_keys). The current value is shown in the dashboard.
ExpirationOptional at creation (90 / 180 / 365 days or no expiration). If the company has set default_expiration_days and you don’t ask for an explicit expiration, the key still expires under that policy.

Check expires_at in the creation response. It is the only reliable source: even if you don’t ask for an expiration, your company’s default_expiration_days policy may have given the key a date. Note it down and schedule the rotation.

Scopes

Each key carries explicit scopes (least privilege). Without the required scope, the endpoint responds 403 invalid_scope.

ScopeAllows
org:empleados:readRead employees.
org:empleados:writeAdd, update and offboard employees.
org:fichajes:readRead check-ins and work summaries.
org:fichajes:writeRecord check-ins.
org:ausencias:readRead absences.
org:ausencias:writeCreate, approve and reject absences.
org:saldos:readRead vacation balances.
org:estructura:readRead locations and units.
org:informes:readRequest and download reports.
webhooks:manageManage outbound webhooks.

GET /v1/organization does not require a specific scope: it is used for introspection and to validate the key. Reports additionally require the read scope of their domain: e.g. absences_export requires org:ausencias:read.

Grant each integration only the scopes it needs.

Sandbox

kinmu_sk_test_ keys always operate against a sandbox company with synthetic data, isolated from your real data. See the Sandbox guide.

Disabling the Public API addon revokes ALL of the company’s API keys (reason addon_disabled) and deletes the sandbox company along with its data. Re-enabling it does not bring them back: new keys have to be issued. See lifecycle.

Rotation

There is atomic rotation: one click in the Kinmu dashboard (Developers → API keys) issues the replacement key keeping the scopes, name, environment and expiration policy and revokes the previous one in the same transaction. You get the new secret once, as with a creation. The /v1 API does not expose key management: creating, rotating and revoking keys is always done from the dashboard.

An already revoked key cannot be rotated: to replace it, create a new one.

If you prefer to overlap both keys to deploy without downtime, do it by hand:

  1. Create the new key with the same scopes.
  2. Deploy your integration with the new key.
  3. Verify that it works (for example, a GET /v1/organization).
  4. Revoke the old key.

Revocation

Revocation is immediate from the dashboard: the key stops working on the next request (401 unauthenticated). Immediately revoke any key you suspect is compromised and review its last_used_ip.

Revoking keys and webhooks (DELETE) works even while the subscription is inactive: it is a security control, not service usage. You are never left unable to cut off a compromised credential.

Best practices

  • Never publish a key in client code, mobile apps, repositories or logs. They are server credentials.
  • Store them in a secrets manager or environment variables.
  • Use one key per integration so you can revoke granularly.
  • Apply least privilege: only the essential scopes.
  • Set an expiration and rotate periodically.
  • In logs, never record the Authorization header.

Authentication errors

HTTPcodeCause
401unauthenticatedMissing key, or the key is invalid, revoked or expired.
403invalid_scopeThe key lacks the required scope (errors.required_scope).
403subscription_inactiveCompany suspended or archived, no subscription, suspended subscription, expired trial, or a canceled and lapsed or expired subscription. Always 403, never 402.
403addon_disabledThe Public API addon is not active.

See the full error format in Conventions → Errors.

Last updated on