Skip to main content

Rate Limiting

The GraphQL API applies an upper bound to the processing time consumed by a single client and applies a token bucket algorithm. We also limit the number of operations this API may perform for a given user at a time, and how complex the queries may be. This is done both to ensure everyone has fair access to the API and to prevent any one party from abusing this access. If requests are made that push you beyond these set limits, you will begin to see errors being returned in the response that correlate to any limits that you may have reached.

While we have set the limits as specified below for now, we may update them in the future as we gather more information and we encourage any feedback you may have about them. Any changes we make to these limits will be announced on this page prior to taking effect, and will be mentioned in our Changelog as well.

Zenhub Enterprise

Zenhub Enterprise rate limits are configurable, but the values listed below apply as default values for this configuration.

Processing Time Limits

As mentioned above, we set an upper bound on the processing time that a single client can consume in a given time period. This method prevents a single client from consuming too much processing time, regardless of whether it comes from a burst of short-lived queries or a small number of long-running queries. It pays no attention to the structure of the incomming request and rather simply measures the time spent on the request as a whole. The query is stopped when a client consumes more than the allowed limit.

Since we use a token bucket algorithm for keeping track of how much of this limit a user has used up, there is not a singular reset time. Rather, we continually replenish a portion of this limit until the bucket is "full", or in other words has the full limit available to be used. Each request uses up a portion of this limit.

To make it easy for you to keep track of these limits and avoid going over, we add the following headers to each response from the API.

Header NameDescription
X-RateLimit-LimitTotal amount of processing time allowed per minute
X-RateLimit-UsedTotal amount of processing time used by the request
X-RateLimit-RemainingTotal amount of processing time remaining in your bucket

For each Personal API Key you have, you are granted 90 seconds of processing time per minute.

Concurrent requests limit

Alongside the processing time limits, we also have a limit on the number of concurrent requests to the API. Every token can execute a maximum of 30 requests concurrently and an error will be returned when this number is exceeded.

Complexity Limits

In order to protect our API from queries which are too complex and resource intensive, we have set a limit on the complexity of any given query. The maximum complexity for a single query is capped at 200. When a query is executed, we calculate the complexity for that query and halt execution of it once it reaches the set maximum. Each property is 1 point, each object is 1 point, and any connection multiplies its children's points based on the given pagination arugment.

For example, this query has a complexity of 25:

query workspaceIssues($workspaceId: ID!) {
  workspace(id: $workspaceId) {
    # +1
    issues(first: 10) {
      # +1
      nodes {
        # +10 (+1, multiplied by `first:` above)
        id # +10 (same resoning as above)
      pageInfo {
        # +1
        hasNextPage # +1
        endCursor # +1

Avoiding Hitting Limits

It's not fun running into issues with limits and we want you to be able to enjoy using this API. We've done our best to set reasonable limits based on how we'd expect people to use this API, but there are undoubtedly situations that come up which will result in users being right up against these caps. If this is you, perhaps try one of the following means of avoiding these limits.

Ask Only for What You Need

The beauty of a GraphQL API is that you can specify exactly the fields that you need. The more fields you ask for, the more complex the query becomes and the longer it'll take to process. Avoid fetching data you don't need. You may even be able to eliminate entire entries in a list by taking advantage of filter parameters that may be available on the query.

Avoid Polling

One thing that's sure to use up your processing time is polling the API to fetch updates. If you need to know when data changes, consider using our Webhook to get notified.

Craft Specific Queries

While it's possible in our graph to drill down pretty deep into some of these fields (such as Workspaces), there's often a means of fetching deeply nested data via a root-level query. Doing so can help to reduce the complexity of the resulting query and allow you to fetch more data before running into issues witih limits.