Skip to content
DikoAPI
API keys

Rate limits

Open as Markdown

Request and import limits, the limit headers and what to do on a 429.

How limits work

Limits protect the API and other users from a client that has gone wrong. Every policy is a token bucket: the capacity says how many requests you can send at once and the refill says how many come back over time. For example, the read policy lets you send 10 read requests at once and then about 5 per second.

Policy Applies to Capacity Refill
read the API key 10 5 / s
write the API key 5 1 / s
imports the API key 5 30 / min
account the billing tenant: the paying team on a team plan, otherwise the user (all keys and members together) 20 10 / s
export (format=text, srt, vtt) the billing tenant, as for account 10 1 / s
me (GET /me only) the API key 5 1 / s
auth_failures a trusted IP (IPv6: the /64 network) 20 20 / min

The billing tenant is the team that pays for the plan when you use a team plan, otherwise it is you. So on a team plan the account and export buckets are shared by every key of every team member, and creating more keys or inviting more members does not give you more capacity. The read, write, imports and me policies stay per key.

The export policy is charged before the transcript is read, so a request that ends in 404 also uses one of its tokens.

One request can fall under several policies. A read counts against both read and account; GET /me counts against read, account and me; POST /library/imports counts against write, imports and account. The policies of every endpoint are in the API reference.

In addition:

  • up to 2 concurrent requests per account (all your keys together); on a team plan the whole team shares a limit of 3 concurrent requests; beyond that you get 429 rate_limit_exceeded with details.policy = concurrency;
  • GET /me has its own limit (the me policy): a burst of 5, then 1 request per second;
  • database work goes through a shared guard, so under load the API can return 503 service_unavailable with Retry-After: 2. That is not your mistake: just retry.

The limits.rate field of the GET /me response lists the policies that apply to the key (read, write, imports, account, me and export) with their burst and refill. The numbers are the same for every key; whose bucket they are counted against is in the table above. The auth_failures policy and the concurrency limit are the ones in the table and the list above.

Limit headers

Every response to an authenticated request that reached the limiter reports the limit state in two ways: following the IETF RateLimit draft and with the widely used X-RateLimit-* headers. Responses that are rejected before the limits are applied (a missing or invalid key, an IP that is not allowed, an unknown route, a wrong method, a body that is too large, of the wrong type or not received in time) carry no limit headers.

HTTP
RateLimit-Policy: "read";q=10;w=2, "account";q=20;w=2
RateLimit: "read";r=7;t=1
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 7
X-RateLimit-Reset: 1
Header Meaning
RateLimit-Policy the policies that apply: q is the capacity, w the window in seconds
RateLimit the most limiting policy now: r is the remaining requests, t the seconds until the next token
X-RateLimit-Limit the capacity of that policy
X-RateLimit-Remaining requests left
X-RateLimit-Reset seconds until the next token

When you get a 429

When a limit is exceeded the API returns 429 rate_limit_exceeded with a Retry-After header (whole seconds, at least 1, until the next token). error.details.policy names the exceeded policy:

JSON
{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Too many requests. Slow down and retry after the time in Retry-After.",
    "doc_url": "https://diko.app/en/api-docs/errors#rate_limit_exceeded",
    "details": { "policy": "read", "retry_after": 1 }
  },
  "request_id": "req_QBPIQ5QTIWAUYTMDNCLD7CMKBE"
}

What to do:

  1. Wait Retry-After seconds and add a little random jitter so several clients do not retry at the same moment.
  2. Keep at most 2 requests in flight at once for the whole account: the limit counts all your keys together, and on a team plan all team members’ keys.
  3. Read lists in large pages (limit=100) and follow has_more instead of fetching items one by one.
  4. Instead of polling, use webhooks or GET /events.

The retry helper code is on the Errors page.

Import capacity

Imports have an extra guard because they use credits and the processing queue. Each decision is made when the import is created:

Limit Value
Active imports of a user (queued, processing, canceling) up to 10
Active imports across all users up to 200
Imports of a user per day (the last 24 hours) up to 500

The daily limit counts every import created in the last 24 hours, including imports that were answered from your library or from Diko’s shared cache (reused: true). Those cost no credits, but they are still imports.

When any limit is exceeded the API returns 429 queue_limit_exceeded with Retry-After: 60. error.details.limit says which limit it was: user_active_imports, capacity (all users) or user_daily_imports. Wait until some imports finish instead of sending more requests.

JSON
{
  "type": "error",
  "error": {
    "type": "rate_limit_error",
    "code": "queue_limit_exceeded",
    "message": "Too many imports are queued or running. Retry later.",
    "doc_url": "https://diko.app/en/api-docs/errors#queue_limit_exceeded",
    "details": { "limit": "user_active_imports", "retry_after": 60 }
  },
  "request_id": "req_QBPIQ5QTIWAUYTMDNCLD7CMKBE"
}

Authentication failure limit

The auth_failures policy limits attempts with bad keys from the same trusted IP. A shared budget also applies to checking keys never seen before, so attempts to guess keys get invalid_api_key with no extra information. Sending the same bad key again is pointless.

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

Search across all documentation pagesesc close