Jira API rate limit: read the headers, then see what CogniRunner spends each hour
Mihai Perdum
Author
13 min readOctober 3, 2026
Key takeaways
END STATE: you can read the Jira API rate limit headers on any call you make, you know which of the three limits a 429 names, and you can open CogniRunner's Settings, Maintenance (or its REST report) and see what the app spent, hour by hour and by component, for the last 14 days.
A curl with an API token shows only the per-second burst headers (that's what our 200s carried). Atlassian says API token traffic is not part of the points model, so your own calls can't show you an app's hourly points spend.
The points maths is small: 1 per request, plus 1 per object on a read, plus 2 per user or group, and 1 for any write. One CogniRunner listener run on our test site cost 2 requests and 3 points, measured twice.
CogniRunner's figures are floors and estimates, and the screen says so. Atlassian's own count is the one that holds.
The allowance-type chip said 'Allowance type not yet observed' on both our sites. My header parser reads the pool's policy line only under its Beta- name, so treat that chip as unknown, not as proof of a shared pool.
Jira Cloud's API rate limit is three limits at once, an hourly points quota, a per-second burst limit and a per-issue write limit, and when any of them trips the REST API answers 429 Too Many Requests with headers that say which one. What Jira doesn't give you is a screen that says which app spent the quota. There's an open suggestion for exactly that, AX-1883, with 49 votes and 43 watchers, and it's still Gathering Interest.
So I built the screen into CogniRunner, our Jira workflow app. One listener run on our test site cost 2 requests and 3 points, and the meter showed it within a minute. I ran it twice and got the same answer twice. On our demo site the busiest hour of the last day was 13,132 points, 20.2% of Atlassian's 65,000 reference.
This tutorial does it in order. First the headers on a call you make yourself with curl, then what a 429 tells you, then the app's own numbers. One thing I got wrong is in there too, and it's about a chip on the screen.
Note
Prerequisites
A Jira Cloud site and an Atlassian API token for an account on it. The curl steps ran on our test site, wolfaenpak, on 2 October 2026.
curl and jq. I used the ones that ship with macOS plus jq from Homebrew.
For steps 3 to 6: CogniRunner installed from the Marketplace listing, at version 5.0.0 or later. The API allowance screen first reached Marketplace customers in 5.0.0 (30 September 2026); the screenshots below are from 6.0.0, released 2 October.
A CogniRunner admin account. The screen and the REST report are admin-only.
How the Jira Cloud API rate limit works: hourly quota, burst and per-issue writes
Atlassian's rate limiting page (I read it on 2 October, it says "Last updated Oct 1, 2026") puts it in one line: "Jira Cloud enforces three independent rate limiting systems that work simultaneously". Enforcement of the points model started on 2 March 2026, for Forge, Connect and OAuth 2.0 (3LO) apps.
The hourly quota is counted in points. "Each request starts with a base cost of 1 point, and additional points are added for each object involved." A read of one issue is 2 points. A read that returns 8 users is 17 (users and groups cost 2 each). Any write is 1, whatever it touches. Cheap, until a job loops. The quota resets at the top of each UTC hour.
By default an app sits in Tier 1, the Global Pool. In Atlassian's words: "Your app shares a single 65,000 point hourly quota across all tenants." Tier 2 gives an app a pool per site, sized by edition and user count, and you don't get it by asking. Atlassian decides. "Only apps with exceptionally high or concentrated usage patterns may be assigned to the Per-Tenant Pool after review."
The other two work on seconds, not hours. Burst is per site and per API path, with a default of 100 requests a second for GET and POST, and 50 for PUT and DELETE. Per-issue writes allow 20 writes to one issue in 2 seconds, and 100 in 30.
one curl to /rest/api/3/myself, filtered to the rate-limit lines.
2
Learn what a 429 names
the RateLimit-Reason value tells you which of the three limits you hit.
3
Open Settings, Maintenance in CogniRunner
the API allowance card says how much of this hour is spent.
4
Read the hourly chart and What spent the points
which part of the app spent it, for 24 hours up to 14 days.
5
Make one known thing happen and watch the hour move
a listener run, measured before and after.
6
Export the hours
the REST report and the evidence file with curl, and the audit log as CSV.
Read the Jira rate limit headers on your own call with curl
Start with what you can see without any app. Put your token in an environment variable, then make one call and keep only the rate-limit lines. Replace the email and the site with yours.
bash
1exportJIRA_API_TOKEN='<your API token>'2curl-sS-o /dev/null -D - -u"you@example.com:$JIRA_API_TOKEN"\3"https://your-site.atlassian.net/rest/api/3/myself"|grep-i-E'^HTTP|ratelimit|retry-after'
Run it twice. This is what our test site printed, both calls:
You should see x-ratelimit-remaining drop by one per call. It refills within the second (t=1). Fine so far. Now the same thing against search, sent as a POST. If you still call the old /rest/api/3/search, it's gone; this is the move to /search/jql.
bash
1curl-sS-o /dev/null -D - -u"you@example.com:$JIRA_API_TOKEN"-H'Content-Type: application/json'\2-X POST "https://your-site.atlassian.net/rest/api/3/search/jql"\3-d'{"jql":"created >= -30d ORDER BY created DESC","maxResults":50,"fields":["summary"]}'|grep-i-E'^HTTP|ratelimit|retry-after'
Three things to notice. The limit is per path: 350 on /myself, 200 on search. The policy line says q=100, while limit and r say 350 and 200. The docs don't explain the gap. I looked, and I won't guess.
And there's no hourly line at all. No global-app-quota, no points. That's by design. Atlassian: "API token-based traffic is not affected by this change, and will continue to be governed by existing burst rate limits." Your scripts aren't on the points model; Atlassian keeps them on the burst limits. Apps live on points. The points quota belongs to apps, and only the app sees its points headers. That's the whole reason an admin is blind here.
What a 429 Too Many Requests from the Jira REST API tells you
When a limit trips you get a 429, and three headers turn up that only come with a 429: Retry-After (seconds to wait), X-RateLimit-Reset (when the window resets, as a timestamp) and RateLimit-Reason. The reason is the useful one. It's one of four values:
RateLimit-Reason
which limit
what to do
jira-quota-global-based
the hourly points quota, shared pool (Tier 1)
stop; nothing passes until the next UTC hour
jira-quota-tenant-based
the hourly points quota, per-site pool (Tier 2)
same
jira-burst-based
per second, per path
wait the Retry-After seconds, back off with jitter
jira-per-issue-on-write
too many writes to one issue
slow down the writes to that issue
5 rows × 3 columnsHeader row enabled
The quota ones hurt. A lot. Atlassian's FAQ says it flat: "All requests are denied until the next hourly reset. There is no gradual throttling." A burst 429 costs you a second. A quota 429 can cost the rest of the hour, for every site sharing that app's pool.
I didn't produce a 429 for this article, and you shouldn't either. Same page: "Do not perform rate limit testing against Atlassian cloud tenants, as this may impact customers." Your check here is reading, not provoking: confirm which header names your site sends, and that your code reads RateLimit-Reason before it decides how long to wait.
Open Settings, Maintenance and read the API allowance
Now the app side. In Jira, open Apps, CogniRunner, then the Settings tab and its Maintenance view. The top card says which build you're on. If Settings has no Maintenance view at all, your site is still on 4.x: the view, the API allowance and the audit log arrived in 5.0.0. Check the version under Manage apps and approve the update.
Marketplace version 6.0.0 on our demo site. The v1.27.0 is our release-notes numbering; 6.0.0 is the Marketplace version.
Scroll to API allowance. The latest report reads as a sentence, and you should see one of five states: Nothing recorded yet, Inside the allowance, Close to the allowance this hour, Atlassian refused requests in the last 24 hours, or Showing the previous report.
Inside the allowance: 226 points so far this hour, 0.3% of the 65,000 reference. Captured on our demo site, CogniRunner 6.0.0.
Read the line under the numbers. The 65,000 is a reference, Atlassian's documented default, not a quota anyone confirmed for your site. The screen says that when Atlassian's answer names a real limit, the app uses that number instead. Today that number only comes from the Beta- form of Atlassian's policy header (the end of this article explains why that matters), so expect the 65,000 to stay. Background work budget says Off because the app has no budget of its own yet. I left it null rather than invent one.
See which app spends your Jira Cloud API usage, hour by hour
This is the view AX-1883 asks Atlassian for, for one app. The description on that ticket is blunt: "Tenant admins are completely blind to API consumption across their instance." Jira still won't show you every app. CogniRunner shows you itself.
Scroll down to Hourly spending. Pick 24 hours, 3 days, 7 days or 14 days. Each column is one UTC hour, stacked by what spent it, and a column outlined in red had requests refused. Under it, What spent the points ranks the parts of the app, heaviest first.
39,623 points in 24 hours, and 95.7% of it from the admin screens. That afternoon includes our own test and screenshot sessions on the demo site, so it is an admin-heavy day, not a typical one.
Look at that list before you blame anything. On the demo site, Admin and rule editor spent 37,927 of 39,623 points. That's the app's own screens calling Jira through its backend, whoever or whatever is driving them. Atlassian staff confirmed on the developer community thread about the 2026 limits that calls a Forge app makes through its backend count toward the points. Direct browser calls through @forge/bridge with no backend don't, for now; staff say that may change with notice. So yes, an admin working through the app's screens costs points whenever a screen asks Jira for something. (That afternoon overlaps our own test and screenshot runs on the demo site.)
There are 16 parts the meter can name: validators, conditions, the two kinds of post-function, listeners, scheduled jobs, the AI agent, the Coder, the Virtual Administrator, the admin screens, the Rules REST API, git webhooks, the five-minute tick, the background queue, Confluence, and other. If you run listeners and scheduled jobs, they get their own lines. A job that reads a few hundred issues every hour shows up here first.
Point at a column, or focus the chart and use the arrow keys, to read one hour. That's how you match a spike to a time you remember.
Make one known thing happen and watch the hour move
A meter you haven't checked is a story. So check it. Pick something you can predict. You need a project where one of your CogniRunner listeners fires on issue created. On our test site that's project TPP, with a listener that reads the new issue and copies the reporter into the assignee. No AI, one read and one write. By Atlassian's maths that's 2 points for the read (base plus one issue) and 1 for the write. Three points.
This part ran on the development build of CogniRunner on wolfaenpak, our test site. The REST report it reads is the same one production serves (step 6 says how to get yours). First, the current hour:
Then create one issue in that project, which fires the listener. Put your project key where it says YOUR-KEY:
bash
1curl-sS-u"you@example.com:$JIRA_API_TOKEN"-H'Content-Type: application/json'\2-X POST "https://your-site.atlassian.net/rest/api/3/issue"\3-d'{"fields":{"project":{"key":"YOUR-KEY"},"issuetype":{"name":"Task"},"summary":"rate limit meter test"}}'| jq -r .key
On ours it printed:
text
1TPP-61
Wait about 45 seconds and run the first command again:
The listener line went from 2 requests and 3 points to 4 and 6. One run, 2 requests, 3 points, exactly the published model. An earlier run on another issue, at 19:18, gave the same 3. The hour total moved by 6, not 3, because the hour also carries everything else the app did in that minute, my own report calls included.
Delete the test issue when you're done, with the key it printed. You should get a 204:
bash
1curl-sS-o /dev/null -w'%{http_code}\n'-u"you@example.com:$JIRA_API_TOKEN"\2-X DELETE "https://your-site.atlassian.net/rest/api/3/issue/<the key it printed>"
text
1204
My API-token account could create in that project but not delete, so I gave it the project's Administrators role for the delete and took it away again.
Do the same with something on your site you can predict: a validator on one transition, or a job you run by hand. If the line for that part doesn't move, the meter's not seeing it, and that's worth knowing before you trust the chart.
Export the hours: CogniRunner's REST API report and the audit-log CSV
The screen is for looking. For a script, a ticket to Atlassian support or a monthly report, use the REST API. An app admin opens Settings, Providers, scrolls to API access, and clicks + Create token. Pick the Admin role, because the usage report is admin-only. The same panel shows the endpoint URL. Put both in your shell:
bash
1exportCGR_REST_URL='<the URL from Settings, API access>'2exportCGR_TOKEN='<the cgr_ token you created>'3curl-sS-H"Authorization: Bearer $CGR_TOKEN"\4"$CGR_REST_URL?resource=platform-usage&days=1"\5| jq '.summary | {totalEstPoints, totalRequests, peakHour, peakHourEstPoints, total429s, top: [.topSources[] | "\(.label): \(.estPoints) points, \(.requests) requests"]}'
days goes up to 14. The evidence file is the one to attach when you ask Atlassian about your quota. On the screen it's the Export evidence button, and over REST it's one more call:
1{
2 "pool": {
3 "current": null,
4 "history": []
5 },
6 "last429": null,
7 "method": "1 point per request, plus 1 per object returned on reads and 2 per user or group returned; every write costs 1. Atlassian's documented points model, applied per response the app received.",
8 "caveats": 6
9}
You should see last429: null on a quiet site. The file states its own method, so whoever reads it at Atlassian knows how the numbers were made.
The audit log is a separate tab, next to Settings. It records what people did in the app and what the app did by itself, and keeps 60 days. Export it as CSV with Current selection or All audit entries. One behaviour I care about: if the export can't read every matching entry, it refuses and says "No file was saved". A partial audit file that looks complete is worse than none.
If it didn't work
what you see
why
fix
401 from the report URL
the token was revoked or mistyped (mine answered 401 right after I revoked it)
create a new token in Settings, API access
403 "You do not have permission to delete issues in this project."
your account can create but not delete in that project
ask a project admin to delete it, or use a project where you hold Delete issues
{"error":"method POST not allowed","reason":"read-only"}
the usage report only answers GET
drop -X POST and the body
Nothing recorded yet
recording starts when your site runs a version with the meter, and hours roll up on a five-minute tick
wait a few minutes and click Refresh
a gap in the chart before a date
same: "Hours before that were not measured"
nothing; it's not zero use, it's no data
6 rows × 3 columnsHeader row enabled
Where I was wrong: the allowance-type chip
Open Allowance ownership and technical evidence. The chip on both our sites says "Allowance type not yet observed". The text under it says it "fills in by itself the first time" Atlassian names the pool on a response.
The chip still reads Allowance type not yet observed. Notice the newest headers box: limit and remaining, but no policy line. Captured on our demo site, CogniRunner 6.0.0.
Look at the newest headers box. It kept limit and remaining and nothing else. While writing this I read my own parser again. It reads the pool's name in two places: the Beta-RateLimit-Policy line, and the RateLimit-Reason on a quota 429. It never reads the un-prefixed RateLimit-Policy. Atlassian's page says "At enforcement Beta- prefix will be dropped from all beta headers", and the curl in step 1 already shows ratelimit-policy with no prefix. If the app's points headers arrive the same way, the only thing that fills the chip today is Atlassian refusing the app for quota. That's the one time you least want to find out.
I haven't proven which form CogniRunner's own responses carry, because the parser drops the un-prefixed policy line before it stores anything. So it's not settled. What I am saying is that the screen's promise is ahead of the code. Until that's fixed, read "not yet observed" as "unknown". It isn't proof you're in the shared pool. The pool is never guessed from silence, and that part works as designed. The guessing would be yours.
What these numbers are, and what they aren't
Every figure is the least CogniRunner used, not the total. I treat them as floors. The screen says that in six short points under What these numbers are, and I'd rather you read them than trust a chart. The ones that matter:
Objects are counted only when the app reads a response body. A run that Atlassian stops before it finishes, or whose count couldn't be saved, is left out. Points are an estimate made with Atlassian's published model, and "Atlassian's own count is the one that holds." Requests made on behalf of a person are counted separately and priced the same, because it isn't confirmed whether they draw on the app's points. And compute is an estimate too.
It's one app. Only one. If three other apps share your site, this screen tells you nothing about them. That's still AX-1883's job, and it's still Gathering Interest. Vote for it if you're an admin.
The Jira curls in steps 1 and 5 ran on our test site, straight against Jira. The CogniRunner report calls in steps 5 and 6 hit the development build there. The screenshots are from the production install on our demo site, at 6.0.0. No step produced a 429 on purpose, so the red-outlined column and the Last refusal line are things I know from the code, not from a live refusal. More on the app itself is on the CogniRunner page.
Recap
Key takeaways
You can read the burst headers on any call you make, and you know your own API-token calls don't carry the hourly points headers today.
You know the four RateLimit-Reason values, and that a quota 429 blocks everything until the next UTC hour.
You can open Settings, Maintenance and see what CogniRunner spent, per hour and per part of the app, for up to 14 days.
You checked the meter against one thing you could predict, and you can pull the same report and the evidence file with curl.
Not covered: other apps on your site, a live 429, and the pool chip, which you should read as unknown for now.
Jira automation rules API and cloud-to-cloud migration: two new agent skills