Skip to content
DikoAPI
API keys

Errors

Open as Markdown

One uniform error format, the catalog of every code and the retry matrix.

Error format

Every 4xx and 5xx error has the same JSON format:

JSON
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_parameter",
    "message": "limit must be between 1 and 100.",
    "param": "limit",
    "doc_url": "https://diko.app/en/api-docs/errors#invalid_parameter"
  },
  "request_id": "req_QBPIQ5QTIWAUYTMDNCLD7CMKBE"
}
Field Meaning
type always error
error.type error class, for example invalid_request_error
error.code stable machine-readable code. Every code is described in the code catalog
error.message human-readable explanation
error.param name of the offending parameter, when one applies
error.doc_url link to the description of this code on this page
error.details extra context only when relevant: required_scopes, granted_scopes, required_plans, policy (rate limits), limit (which import limit queue_limit_exceeded hit), retry_after
request_id request ID (req_...). Quote it when you contact support

Classes and HTTP statuses

Headers worth reading

Header When What to do
Request-Id (and X-Request-ID) always keep it in your log; it equals the request_id field
X-Client-Request-Id when you sent one Diko echoes back the value you sent in the request header of the same name (1 to 128 characters from A-Za-z0-9._:-; any other value is ignored). Use it to match a response to your own log entry
Retry-After 429, 503 and idempotency_in_progress wait that many whole seconds (at least 1)
WWW-Authenticate 401 and insufficient_scope names Bearer realm="diko"; for insufficient_scope also the required scope
Allow 405 lists the permitted methods

Retry matrix

Retry only when it makes sense. Errors caused by the request itself do not go away on retry.

Situation Retry? How
Network error or timeout (no response received) yes backoff with jitter; always the same Idempotency-Key for POST
408 request_timeout yes the body did not arrive in time (10 s by default); the request created nothing, so send the same request again with the same Idempotency-Key. If it keeps happening, check your connection and send the body in one piece
400, 404, 405, 413, 415, 422 no fix the request (parameters, ID, body, Content-Type, Idempotency-Key)
401, 403 no check the key, scopes, plan, IP and account state
402 no, until resolved pay for a plan or top up credits; then the request can be repeated
409 idempotency_in_progress yes, after Retry-After the same request with the same key
409 resource_not_ready yes, later wait for meeting.ready or check transcript.status
409 transcript_changed yes, from the start read the transcript again without a cursor
409 import_not_cancelable no the import has already finished
429 yes, after Retry-After never sooner; use backoff
500 yes, 2 or 3 times with backoff; if it persists, report it with the request_id
503 yes, after Retry-After for writes_disabled usually after 300 s
404 api_disabled later the API is temporarily switched off

Retry recipe

This helper retries 408, 429, 500 and 503, honours Retry-After and otherwise uses exponential backoff with jitter. For POST pass the same Idempotency-Key to every attempt.

Python
import random
import time

import requests

RETRYABLE = {408, 429, 500, 503}


def request_with_retry(method, url, *, max_attempts=5, **kwargs):
    for attempt in range(1, max_attempts + 1):
        try:
            response = requests.request(method, url, timeout=30, **kwargs)
        except (requests.ConnectionError, requests.Timeout):
            if attempt == max_attempts:
                raise
            delay = min(2**attempt, 30)
        else:
            if response.status_code not in RETRYABLE or attempt == max_attempts:
                return response
            retry_after = response.headers.get("Retry-After", "")
            delay = int(retry_after) if retry_after.isdigit() else min(2**attempt, 30)
        time.sleep(delay + random.uniform(0, delay * 0.2))

Code catalog

Every code has its own anchor, for example #invalid_parameter, so the doc_url link leads straight to its description.

CodeHTTPTypeRetry
invalid_request400invalid_request_errorno
invalid_parameter400invalid_request_errorno
invalid_cursor400invalid_request_errorno
invalid_youtube_url400invalid_request_errorno
api_key_in_query400invalid_request_errorno
idempotency_key_invalid400invalid_request_errorno
missing_api_key401authentication_errorno
invalid_api_key401authentication_errorno
api_key_expired401authentication_errorno
api_key_revoked401authentication_errorno
api_key_disabled401authentication_errorno
subscription_required402billing_errorno
insufficient_credits402billing_errorno
team_member_limit_reached402billing_errorno
insufficient_scope403permission_errorno
plan_required403permission_errorno
ip_not_allowed403permission_errorno
account_disabled403permission_errorno
email_not_verified403permission_errorno
api_access_suspended403permission_errorno
team_member_disabled403permission_errorno
not_found404not_found_errorno
route_not_found404not_found_errorno
api_disabled404not_found_errorconditionally
method_not_allowed405invalid_request_errorno
idempotency_in_progress409conflict_erroryes, after Retry-After
import_not_cancelable409conflict_errorno
transcript_changed409conflict_errorconditionally
resource_not_ready409conflict_erroryes
request_timeout408invalid_request_erroryes
request_too_large413request_too_largeno
unsupported_media_type415invalid_request_errorno
idempotency_key_reused422invalid_request_errorno
rate_limit_exceeded429rate_limit_erroryes, after Retry-After
queue_limit_exceeded429rate_limit_erroryes, after Retry-After
internal_error500api_errorconditionally
service_unavailable503service_unavailable_erroryes, after Retry-After
credit_balance_unavailable503service_unavailable_erroryes, after Retry-After
writes_disabled503service_unavailable_erroryes, after Retry-After

invalid_request

HTTP 400Type: invalid_request_errorRetry: no

The request is malformed: the body is not valid JSON, is missing, is not a JSON object, or Content-Length is not a number. A missing required field or an unknown field is invalid_parameter instead.

What to do. Send a JSON object and compare it with the endpoint schema.

invalid_parameter

HTTP 400Type: invalid_request_errorRetry: no

A path, query or body parameter has an invalid value, a required field is missing or a field is unknown (unknown fields are rejected). error.param names the parameter.

What to do. Fix the parameter according to its constraints, for example limit must be between 1 and 100.

invalid_cursor

HTTP 400Type: invalid_request_errorRetry: no

The cursor is corrupted or was issued for another user, route, sort order or set of filters.

What to do. Start paging again without a cursor and keep the filters unchanged between pages.

invalid_youtube_url

HTTP 400Type: invalid_request_errorRetry: no

The URL is not a supported address of a single YouTube video.

What to do. Use a link from youtube.com, www.youtube.com, m.youtube.com, music.youtube.com or youtu.be.

api_key_in_query

HTTP 400Type: invalid_request_errorRetry: no

The key was sent in the query string (api_key, key, token or access_token).

What to do. Send the key only in the Authorization: Bearer header. The key may have reached logs, so rotate it.

idempotency_key_invalid

HTTP 400Type: invalid_request_errorRetry: no

The Idempotency-Key is invalid: it needs 8 to 255 characters from A-Z a-z 0-9 _ - : ..

What to do. Generate a UUID and send it without extra characters.

missing_api_key

HTTP 401Type: authentication_errorRetry: noWWW-Authenticate

The request has no Authorization header.

What to do. Add the header Authorization: Bearer dk_live_....

invalid_api_key

HTTP 401Type: authentication_errorRetry: noWWW-Authenticate

The header is unusable (a scheme other than Bearer, an empty key or more than one Authorization header) or the key is unknown or malformed (wrong structure or checksum). The response is identical in all these cases.

What to do. Send exactly one header Authorization: Bearer <key> and check that you copied the whole key without spaces. If the key is lost, create a new one.

api_key_expired

HTTP 401Type: authentication_errorRetry: noWWW-Authenticate

The key has expired.

What to do. Create a new key in the Diko app and update your systems.

api_key_revoked

HTTP 401Type: authentication_errorRetry: noWWW-Authenticate

The key was revoked: manually, after a rotation grace period ended, because of a leak or because the account was disabled.

What to do. Create a new key and update your systems. A revoked key cannot be restored.

api_key_disabled

HTTP 401Type: authentication_errorRetry: noWWW-Authenticate

The key is temporarily disabled.

What to do. Enable the key in the Diko app (this needs re-authentication) or use another key.

subscription_required

HTTP 402Type: billing_errorRetry: no

The account has no active paid access.

What to do. Choose a plan in the Diko app. The API is available on the Verslas plan.

insufficient_credits

HTTP 402Type: billing_errorRetry: no

There are not enough credits for the import.

What to do. Top up credits and repeat the request. A 402 response is not stored, so you can reuse the same Idempotency-Key.

team_member_limit_reached

HTTP 402Type: billing_errorRetry: no

Your credit limit in the team has been reached.

What to do. Ask the team owner or an administrator to raise the limit.

insufficient_scope

HTTP 403Type: permission_errorRetry: noWWW-Authenticate

The key lacks the scope this endpoint needs. error.details contains required_scopes and granted_scopes.

What to do. Create a key with the required scope. Scopes cannot be changed after creation.

plan_required

HTTP 403Type: permission_errorRetry: no

The plan does not include the API. error.details.required_plans lists verslas.

What to do. Move to the Verslas plan. Keys are not deleted and work again once the plan allows it.

ip_not_allowed

HTTP 403Type: permission_errorRetry: no

The key has an IP allowlist and the request IP is not on it, or it cannot be determined reliably.

What to do. Send from an allowed address or change the list in the Diko app. Check the IP with another key that has no restriction: GET /me → request.

account_disabled

HTTP 403Type: permission_errorRetry: no

The account is disabled.

What to do. Contact Diko support and include the request_id.

email_not_verified

HTTP 403Type: permission_errorRetry: no

The account e-mail address is not verified.

What to do. Verify the e-mail address in the Diko app.

api_access_suspended

HTTP 403Type: permission_errorRetry: no

A Diko administrator suspended API access for this account.

What to do. Contact Diko support and include the request_id.

team_member_disabled

HTTP 403Type: permission_errorRetry: no

Your team membership is disabled.

What to do. Contact the team owner or an administrator.

not_found

HTTP 404Type: not_found_errorRetry: no

The resource does not exist, does not belong to your account or its ID is encoded incorrectly.

What to do. Check the ID. The API deliberately returns 404 rather than 403 so it never reveals whether another account's resource exists.

route_not_found

HTTP 404Type: not_found_errorRetry: no

No such route exists. A path with a trailing / also counts as unknown.

What to do. Check the path and the base URL https://api.diko.app/api/v1.

api_disabled

HTTP 404Type: not_found_errorRetry: conditionally

The public API is currently switched off.

What to do. Try again later. If it lasts, contact Diko support.

method_not_allowed

HTTP 405Type: invalid_request_errorRetry: noAllow

The method is not supported for this path. The Allow header lists the permitted methods. OPTIONS also returns 405 because browser requests are not supported.

What to do. Use one of the methods listed in the Allow header.

idempotency_in_progress

HTTP 409Type: conflict_errorRetry: yes, after Retry-AfterRetry-After

The same request with the same Idempotency-Key is still being processed.

What to do. Wait Retry-After seconds and send the identical request with the same key.

import_not_cancelable

HTTP 409Type: conflict_errorRetry: no

The import has already finished (succeeded or failed) and can no longer be canceled.

What to do. Read the import status. An import that is already canceling or canceled returns 200.

transcript_changed

HTTP 409Type: conflict_errorRetry: conditionally

The transcript changed while you were paging: its revision changed.

What to do. Start reading the transcript again without a cursor.

resource_not_ready

HTTP 409Type: conflict_errorRetry: yes

The transcript does not exist yet: the meeting is still being processed.

What to do. Check transcript.status on the meeting or wait for the meeting.ready event, then try again.

request_timeout

HTTP 408Type: invalid_request_errorRetry: yes

The request body was not received in time (10 s by default). This happens when a client sends the body too slowly or stalls while sending. Nothing was created.

What to do. Send the whole body at once and check your connection. It is safe to repeat the request with the same Idempotency-Key.

request_too_large

HTTP 413Type: request_too_largeRetry: no

The request body is larger than 64 KB.

What to do. Reduce the body. These endpoints never need large bodies.

unsupported_media_type

HTTP 415Type: invalid_request_errorRetry: no

A POST body must be application/json.

What to do. Set the header Content-Type: application/json.

idempotency_key_reused

HTTP 422Type: invalid_request_errorRetry: no

The same Idempotency-Key was used with a different method, path or body.

What to do. Generate a new key for every new operation. Repeat only an identical request.

rate_limit_exceeded

HTTP 429Type: rate_limit_errorRetry: yes, after Retry-AfterRetry-After

A rate-limit policy was exceeded. error.details.policy names it.

What to do. Wait Retry-After seconds. Retry with backoff and jitter, not immediately.

queue_limit_exceeded

HTTP 429Type: rate_limit_errorRetry: yes, after Retry-AfterRetry-After

The import capacity is reached: up to 10 active per user, 200 overall or 500 per day.

What to do. Wait for Retry-After (60 s) or until some imports finish. Do not send more requests while the queue is full.

internal_error

HTTP 500Type: api_errorRetry: conditionally

An internal server error.

What to do. Retry up to 2 or 3 times with backoff (POST with the same Idempotency-Key). If it persists, contact Diko support and include the request_id.

service_unavailable

HTTP 503Type: service_unavailable_errorRetry: yes, after Retry-AfterRetry-After

The service is temporarily busy, for example because of database load.

What to do. Wait Retry-After seconds (usually 2) and try again.

credit_balance_unavailable

HTTP 503Type: service_unavailable_errorRetry: yes, after Retry-AfterRetry-After

The credit balance could not be determined right now, so the import was not started.

What to do. Wait Retry-After seconds and repeat the request with the same Idempotency-Key.

writes_disabled

HTTP 503Type: service_unavailable_errorRetry: yes, after Retry-AfterRetry-After

Write operations are temporarily switched off on the platform side. Reading still works.

What to do. Wait Retry-After seconds (300) and repeat the request with the same Idempotency-Key.

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

Search across all documentation pagesesc close