Rate Limits

To ensure fair usage and protect the stability of the Bokio API, rate limiting is implemented. Rate limiting restricts the number of requests that can be made within a certain time frame. In addition to the standard Rate Limits (requests per minute), the API also enforces Concurrency Limits to ensure data integrity and system stability.

📘

Current limits

  • Bokio API is rate limiting at 200 requests during a 60 seconds rolling window based on the provided bearer token.
  • Bokio API restricts concurrent writes on the same resource. For mode details see, Concurrency limits.

Rate Limit

When making requests to the Bokio API, you will receive the following headers related to rate limiting:

  • Bokio-RateLimit-Limit: The maximum number of requests allowed within the specified time frame.
  • Bokio-RateLimit-Remaining: The number of requests remaining within the current time frame.
  • Bokio-RateLimit-RetryAfter: The time until the rate limit will reset, represented in seconds left.

Handling Rate Limit Exceeded

If you exceed the rate limit, the API will respond with a 429 Too Many Requests status code. This indicates that you have reached the maximum number of requests allowed within the specified time frame.

To avoid this error, make sure to monitor the Bokio-RateLimit-Remaining header in the API response. If the remaining requests reach zero, you should wait until the Bokio-RateLimit-RetryAfter time before making additional requests.

It is recommended to implement proper error handling and back off strategies to handle rate limit exceeded scenarios gracefully.

Here is a suggested update for your documentation page. It introduces the concept of Concurrency Limits alongside your existing Rate Limits to help developers avoid the race conditions we diagnosed.

Concurrency Limits

While Rate Limits restrict the volume of requests over time, Concurrency Limits restrict the number of requests processed at the exact same moment.

Why we limit concurrency

Concurrency limits are critical for endpoints that modify shared resources (such as Journal Entries or Invoices). If multiple requests try to modify the same resource simultaneously, it can lead to:

  • Race Conditions: Two requests reading the same data and trying to update it at the same time.
  • System Errors: You may receive 500 Internal Server Error or 409 Conflict responses if the database locks cannot be acquired.

What happens if you exceed the limit?

When the concurrent write request hit the same url path, for example POST companies/{companyId}/journal-entries, the API will reject the request with a 429 Too Many Requests error.

Example response:

HTTP/1.1 429 Too Many Requests

{
  "statusCode": 429,
  "message": "Concurrency limit exceeded."
}

Best Practices to Avoid Concurrency Errors

  1. Serialize Your Writes:
    Do not send batches of POST or PUT requests in parallel (e.g., using Promise.all() in JavaScript). Instead, send them sequentially: wait for the first request to return 200 OK before sending the next.

    Bad (Parallel):

    // ❌ Risk of Concurrency Limit or 409 Conflict
    await Promise.all([req1, req2, req3, req4, req5]);

    Good (Sequential):

    // ✅ Safe and reliable
    for (const req of requests) {
        await sendRequest(req);
    }
  2. Handle 429 Errors:
    If you receive a 429 status update your application logic to avoid concurrent write requests for the same resource. Note that the rate limit headers do not apply for concurrency limits.