Developing for Atlassian Government Cloud?
This content is written with standard cloud development in mind. To learn about developing for Atlassian Government Cloud, go to our Atlassian Government Cloud developer portal.
This article provides details about rate limiting in Jira to help you anticipate rate limiting and manage how your app responds.
Jira limits the rate of REST API requests to ensure that services are reliable and responsive for customers.
The implementation of rate limiting is centered around tracking the cost of processing requests against various cost budgets. Depending on the type of authentication used, each API request is associated with one of these user-based budgets:
This table provides a mapping of call types to cost budgets.
Call Type | Cost Budget |
---|---|
User (Jira front end initiated action) | User |
JWT (app server to Jira API) | App |
JWT user impersonation | App + user |
Connect app iframe (AP.request) | App + user |
OAuth 2.0 (3LO) | App + user |
Forge asUser() | App + user |
Forge asApp() | App |
Anonymous | Anonymous |
It is important to understand how to design and implement your app in order to ensure it is able to scale for tenants with large numbers of users.
Let’s say we have the following conditions/assumptions:
In the above scenario, the app will be making 100 users * 1 request / 10 seconds = 10 REST API calls per second.
If the app is making the API call in such a way that it counts against the “App” cost budget, then all API calls will be evaluated against the single “App” cost budget of 10 calls per second which means it will be on the brink of being rate limited.
Alternatively, if the app is making the API call in such a way that it counts against the “App + user” cost budget, the API calls will be evaluated against 100 separate “App + user” cost budget contexts of 10 calls per second each. The app will therefore only be making 0.1 calls per second against each of these “App + user” cost budget contexts which is well within the cost budget of 10 calls per second.
The key guideline here is that in order for an app to scale by the the number of users in a tenant, it must be coded such that user activity results in API calls made against the “App + user” cost budget rather than the “App” cost budget.
REST API rate limits factor in both quota and burst based limits.
Quota and burst rate limiting is implemented as a set of rules that consider the app sending the request, the tenant receiving that request, the number of requests, the edition of the product being queried, and its number of users.
The rules are applied independently to burst (10 seconds) and quota (1 hour) periods to determine an appropriate maximum amount of requests. Request processing above the threshold is blocked, including downstream processing.
We will begin enforcing rate limits for all free apps on or after August 18, 2025. However, please note that in circumstances where apps are highly impacting the stability of our platform, we reserve the right to enforce the limits at an earlier date.
Apps can detect rate limits by checking if the HTTP response status code is 429
. Any REST API can return a rate limit response.
429
responses may be accompanied by Retry-After
and X-RateLimit-Reset
headers.
Retry-After
indicates how many seconds the app must wait before reissuing the request. If you reissue the request before the retry period expires, the request will fail and return the same or longer Retry-After
period.
X-RateLimit-Reset
This header provides the timestamp (in ISO 8601 format) when the rate limit will reset, calculated as the request
timestamp plus the Retry-After
period. It's provided in the format: yyyy-MM-ddTHH:mmZ
.
Some transient 5XX
errors are accompanied by a Retry-After
header. For example, a 503
response may be returned when a resource limit has been reached. While these are not rate limit responses, they can be handled with similar logic as outlined below.
Other header responses include:
X-RateLimit-Limit
: This header specifies the maximum number of requests that a user can make within a specific time window.
X-RateLimit-Remaining
: This header shows the number of requests remaining in the current rate limit window before the limit is reached.
RateLimit-Reason
: This header indicates the reason the request was declined. Possible values:
JIRA_COST_BASED
which refers to counter and cost based limits being breached
JIRA_QUOTA_RATE_LIMITED
which refers to API rate limits being breached
X-RateLimit-NearLimit
: indicates that less than 20% of any budget remains. This is a boolean value added to a successful response.
You can retry a failed request if all of these conditions are met:
Retry-After
header or 429
status).Apps should treat 429
responses as a signal to alleviate pressure on an endpoint. Apps should retry the request only after a delay. Best practice to double the delay after each successive 429
response from a given endpoint. Backoff delays only need to exponentially increase to a maximum value at which point the retries can continue with the fixed maximum delay. You should also apply jitter to the delays to avoid the thundering herd problem.
The following articles provide useful insights and techniques related to retry and backoff processing:
There are several considerations that govern the rate limit response handling:
These parameters are influenced by higher-level considerations, such as:
The following pseudo code illustrates the recommended response processing logic:
1 2// Defaults may vary based on the app use case and APIs being called. let maxRetries = 4; // Should be 0 to disable (e.g. API is not idempotent) let lastRetryDelayMillis = 5000; let maxRetryDelayMillis = 30000; let jitterMultiplierRange = [0.7, 1.3]; // Re-entrant logic to send a request and process the response... let response = await fetch(...); if (response is OK) { handleSuccess(...); } else { let retryDelayMillis = -1; if (hasHeader('Retry-After') { retryDelayMillis = 1000 * headerValue('Retry-After'); } else if (statusCode == 429) { retryDelayMillis = min(2 * lastRetryDelayMillis, maxRetryDelayMillis); } if (retryDelayMillis > 0 && retryCount < maxRetries) { retryDelayMillis += retryDelayMillis * randomInRange(jitterMultiplierRange); delay(retryDelayMillis); retryCount++; retryRequest(...); } else { handleFailure(...); } }
Some apps may invoke the REST API concurrently via the use of multiple threads and/or multiple execution nodes. When this is the case, developers may choose to share rate limit responses between threads and/or execution nodes such that API requests take into account rate limiting that may have occurred in other execution contexts. This sharing of rate limit responses should include cost budget information in order to be effective. If the app makes impersonated REST API calls from the app's backend and also calls the API from an app iframe, then this distribution of rate limit response data would logically have to also include the app's iframe(s). Distributing rate limit response data will be non-trivial, so an alternate strategy involves backing off more quickly and/or increasing the maximum number of retries. This second strategy may result in poorer performance and may need tuning if the characteristics of the app changes.
These are some strategies to spread out requests and thereby lower the peaks.
A high level of concurrency in apps may slow the performance of Jira, causing a less responsive user experience. Significant levels of concurrency will also result in a greater chance of rate limiting.
If your app makes many similar requests in a short amount of time, coordination of backoff processing may be necessary.
Although multi-threaded apps may see greater throughput for a short period, you should not attempt to use concurrency to circumvent rate limiting.
When performing scheduled tasks, apply jitter to requests to avoid the thundering herd problem. For example, try to avoid performing tasks “on the hour.” This approach can be applied to many types of actions, such as sending daily email digests.
When you need to perform a large amount of ad-hoc processing, such as when migrating data, you should anticipate and account for rate limiting. For example, if the API calls are directed to a single tenant, it may be possible to schedule the activity at night or on a weekend to minimize customer impact while maximizing throughput.
Consolidating requests lowers the cost by aggregating tasks and reducing overhead. For example, instead of sending a request to create a Jira issue followed by requests that set fields or add properties, a better approach is to use a single request. This case is explained further in the community post POST /rest/api/2/issue (create issue) throws error when passing entity properties.
There are several "bulk" operations that consolidate requests. For example, Bulk create issue.
Many operations also enable queries to be consolidated by specifying expand query parameters.
Jira provides a range of context parameters that can help minimize the number of API requests necessary. Also, note that conditions can be sent as context parameters.
As rate limiting is based on concurrency and cost, minimizing the amount of data requested will yield benefits. An obvious strategy to start with is caching. You can also save resources by specifying which fields or properties to return when using operations such as Search for issues using JQL (GET). Similarly, only request the data you need when using expand query parameters. You can use pagination in your requests to limit the number of matches required. Using webhooks to subscribe to data updates can also lower your data request volume, thereby lowering the risk of rate limiting.
Do not perform rate limit testing against Atlassian cloud tenants because this will place load on Atlassian servers and may impact customers.
The Acceptable Use Policy identifies your obligations to avoid overwhelming Atlassian infrastructure.
The following Jira issues capture known limitation and enhancements relating to rate limiting:
Question | Answer |
---|---|
Can we expect that these rate limits will be adjusted over time by Atlassian? | Yes. In order to continuously ensure that services are reliable and responsive for our shared customers, we reserve the right to adjust these limits at any time and will keep you apprised of any changes. |
Will my app be impacted by rate limits? | We will not begin hard enforcement for all free apps until on or after August 18, 2025. However, in some circumstances where apps are highly impacting the stability of our platform, we reserve the right to enforce the limits at an earlier date. We will notify your listed account contact directly via email if impacted. Please monitor header responses to see where you are at with regard to limits. |
Will this impact Confluence apps as well? What about paid apps? | Yes, you can view the Confluence API rate limit documentation here. Additionally, we are planning to bring clarity to rate limits across our platform infrastructure over the next year, including paid apps. |
How can I tell if I’m getting close to the limits? | For now, please monitor header responses to see where you are at with regards to limits:
|
Will this result in breaking changes? | No. It's important to note that these changes do not break the impacted APIs; instead, it reduces the request limit which means the app may subsequently need to reduce crawl and refresh rates. Please ensure your app is able to handle the header responses as required. |
What error message will customers receive? | Customers will see whichever error message you already have in place to handle API status code 429 as per the API documentation. If you do not have this in place, we recommend the following message:
|
What can I do to reduce API calls? | Please review the API hygiene information above under Lowering the request cost. |
Will customers be notified of this change? | Not at this time. While customers may be impacted, partners will have the capability to address customer inquiries more efficiently and directly on a case-by-case basis. |
Who can I contact if I still have additional questions or need support? | For additional support, please submit a ticket. |
Rate this page: