Skip to content
DikoAPI
API keys

Authentication and keys

Open as Markdown

How to send a key, its format and how the key lifecycle works.

Bearer key

Every request carries an Authorization header with the Bearer scheme. Only GET / and GET /openapi.json need no key:

HTTP
Authorization: Bearer dk_live_...

Rules that protect your key:

  • Only Authorization: Bearer is accepted. The X-API-Key header is not accepted because it would leak through redirects.
  • A key cannot be in the URL. If it is in the query string (api_key, key, token, access_token), the API returns 400 api_key_in_query. Treat such a key as leaked and rotate it.
  • A key is not used in the browser. The API sends no Access-Control-* headers and an OPTIONS request gets 405. Always use the key from your own server.

Key format

A key looks like this: dk_live_ followed by 49 characters from [0-9A-Za-z], 57 characters in total.

Part Length Purpose
dk_live_ 8 prefix that people and secret scanners recognise
random part 43 256 bits of randomness
checksum 6 Base62 CRC32 (big-endian, zero-padded)

Regular expression: ^dk_live_[0-9A-Za-z]{49}$. The checksum lets you reject a typo and spot a key in code without a network request. The prefix dk_test_ is reserved for the future; v1 has no sandbox.

Diko stores only the SHA-256 hash of a key and a hint (dk_live_Ab12…9xYz). The key itself is never written to logs, e-mails or error responses.

Creating keys

You create keys in the Diko app, under Nustatymai → API (Settings → API), at /settings/api. The old /kurejams link still works and redirects there. The form asks for:

Field Requirements
Pavadinimas (Name) 1 to 100 characters
Aprašas (Description) optional, up to 500 characters
Leidimai (Scopes) pick a template or individual scopes; see Scopes. They cannot be changed after creation
Galiojimas (Expiry) 7, 30, 90 (default), 180 or 365 days, or a date. At most 365 days and there is no “never”. You can only shorten the expiry
IP apribojimas (IP allowlist) up to 20 CIDR entries, optional; see Security guidelines for where it works

After creation the key is shown once. The app will not let you close the dialog until you tick Išsaugojau raktą saugioje vietoje (I saved the key in a safe place). Creating, rotating, enabling and changing the IP list may ask you to confirm again (valid for 10 minutes). Revoking, disabling and renaming need no confirmation so that safe actions stay fast.

Limits: at most 25 keys (active and disabled together). Expired and revoked keys, and old keys in a rotation grace period, are not counted. You can create or rotate at most 10 keys per hour.

The key object

GET /me returns the key that made the request. The secret itself is, of course, not shown:

JSON
{
  "id": "key_4Vf9771zpS8JcQdtUcR0u8",
  "object": "api_key",
  "name": "CRM sync",
  "description": "",
  "hint": "dk_live_Ab12…9xYz",
  "scopes": ["meetings:read", "library:read"],
  "status": "active",
  "allowed_cidrs": [],
  "created_at": "2026-10-11T09:00:00.000Z",
  "expires_at": "2027-01-09T09:00:00.000Z",
  "last_used_at": null,
  "last_used_ip": null,
  "first_used_at": null,
  "disabled_at": null,
  "revoked_at": null,
  "revoked_reason": null,
  "rotated_from": null,
  "grace_until": null
}

The rest of the GET /me response follows the same least-privilege rule, so a key handed to a third party does not reveal the account owner’s details: user.email is always masked (j***@example.com) and credits is null unless the key has the library:write scope, the only one that spends credits.

Statuses

Status Meaning
active the key works
disabled temporarily switched off; it can be enabled again (this needs re-authentication)
revoked permanently revoked; revoked_reason says why
expired derived status: expires_at has passed

revoked_reason values: user (you revoked it), rotated (a rotation grace period ended), admin (a team administrator revoked it), owner (the team owner revoked it), user_disabled (the account was disabled), leaked (a leak was detected), dormant (unused for a long time), revoke_all (the Atšaukti visus raktus (Revoke all keys) action).

Expiry, reminders and unused keys

  • Diko sends an e-mail 7 days and 1 day before the key expires (only if the key was valid for at least 14 and at least 2 days).
  • The app marks a key Nenaudojamas (Unused) after 90 days without use. A key unused for 365 days is revoked automatically (dormant).
  • Every key has last_used_at and usage statistics in the app, which makes forgotten integrations easy to spot and revoke. last_used_at is updated at most every 5 minutes, so it can lag behind the real last call.

Rotation

Rotation creates a new key and lets the old one work for a while, so you can update systems without downtime.

  • Grace period: immediately, 1 hour, 24 hours (default) or 7 days.
  • The new key inherits the name, description, scopes and IP list. It keeps the old key’s lifetime (at most 365 days), counted from the moment of rotation.
  • The old key gets grace_until and becomes revoked (rotated) when the time ends.
  • Only one rotation of the same key can be open at a time.

A step-by-step recipe is in the Security guidelines.

Imports when a key stops working

An import created with POST /library/imports can run for minutes. When the key that created it stops working, Diko stops the import too, so a leaked key cannot keep spending credits through work it queued.

  • These actions cancel the key’s imports that are still queued or processing: revoking the key (by you, by a team administrator or owner, with Atšaukti visus raktus (Revoke all keys), or automatically after a leak report from GitHub), disabling it, deleting it, rotating it with the immediately grace period, and disabling the account. Suspending the API access of an account cancels the imports of all its keys.
  • A queued import becomes canceled at once. A processing import becomes canceling and ends canceled when the work stops. Each end sends the event library.import.canceled.
  • A rotation with a grace period (1 hour, 24 hours or 7 days) leaves the imports running, and the old key becoming revoked (rotated) when the period ends does not cancel them. If you revoke the old key yourself during the grace period, its imports are canceled like those of any revoked key.
  • Work already done is charged as usual: a transcript that was already fetched or was finishing still reaches your library.

Plan

The API is available on the Verslas plan (Verslas is the product name of the business plan). In API responses this plan is the value verslas. The plan_required error lists it in required_plans.

GET /me shows the current state in access:

  • access.plan is asmeninis (the personal plan, which does not include the API), verslas or null when the account has no plan;
  • access.allowed says whether API requests are allowed;
  • access.reason says why. Access is granted by subscription, team (a team plan), owner or exempt (accounts that pay nothing), or paywall_off (billing is switched off). Access is denied with subscription_required or plan_required.

The plan is checked on every request, so keys are not removed when the plan changes: they work again when the plan allows. GET /me does not check the plan, so it is the right call for diagnostics.

Authentication errors

Situation HTTP Code
No Authorization header 401 missing_api_key
A scheme other than Bearer, an empty key, more than one Authorization header, a bad format or checksum, or an unknown key 401 invalid_api_key
The key expired 401 api_key_expired
The key was revoked 401 api_key_revoked
The key is disabled 401 api_key_disabled
The IP is not on the key’s list 403 ip_not_allowed
The account is disabled, the e-mail is unverified or API access was suspended 403 account_disabled, email_not_verified, api_access_suspended
No paid access 402 subscription_required
The plan does not include the API 403 plan_required

401 responses carry a WWW-Authenticate header: Bearer realm="diko" when there is no Authorization header, and Bearer realm="diko", error="invalid_token" otherwise.

When a key is revoked, disabled or rotated, the change reaches the API within about 10 seconds.

Search for a topic, an endpoint or an error code.

Search across all documentation pagesesc close