Disclosure: I'm part of the team at UX Software. We build Webhooks Pro for Jira Cloud, so we've spent a long time in this particular corner of the platform. This article is about the platform behaviour first — I've tried to be accurate about what native webhooks actually do, including the parts people underestimate.
Every few weeks someone posts a variation of the same question here: "my Jira webhook isn't working", "can I change what Jira sends?", "how do I know if it was delivered?"
The answers usually jump straight to "use an app". I'd rather start one level down, because a lot of the frustration comes from not knowing exactly where the native feature stops. So: here's an honest map.
This part gets skipped a lot, including by vendors. Native webhooks are more capable than their reputation suggests:
project = OPS AND priority = High and only matching issues fire it. This is built in.X-Hub-Signature header so your receiver can verify the request really came from Jira.If your integration needs "when a high-priority bug is created in OPS, POST it to this URL, signed" — native does that, and you should just use native.
The wall shows up somewhere else.
Native webhooks send a Jira-defined JSON body, over POST, to your URL. That's the whole contract. No method choice, no body shaping, no custom headers, no query parameters.
That's fine when you control the receiver. It stops being fine the moment the receiver is something you don't control and that expects its own shape — Slack, Teams, PagerDuty, a partner's API, an internal service with a strict schema.
Choosing the method, the body, the headers and the query parameters per webhook.
What you end up building: a small middleman service whose entire job is to accept Jira's payload, reshape it, and forward it. Now you're operating a service, with its own hosting, secrets, uptime and on-call, so that a JSON object can change shape.
I've seen a lot of these. They're the single most common piece of accidental infrastructure around Jira.
This is the big one, and it's the reason most "my webhook isn't working" threads are hard to answer.
Native webhooks give you no delivery log. When something doesn't arrive downstream, you can't tell from the Jira side whether:
From inside Jira, all five look identical. So debugging turns into instrumenting the receiver and waiting for the problem to happen again — which, if it's intermittent, can take days.
The same five cases, told apart: a 500 next to a 409 next to a replayed 503, and the receiver's own error body sitting beside the request that caused it.
What you end up building: request logging on the receiver, which only helps for requests that actually reached the receiver. The failures you most need to see are exactly the ones that don't show up there.
This gap is tracked as https://jira.atlassian.com/browse/JRACLOUD-41463 «Webhook logging for Jira» — open since 2014, 450+ votes, still Gathering Interest.
Your receiver was down for twenty minutes during a deploy. Jira fired forty events at it. Those forty events are not coming back.
There's no queue you can drain, no "replay the last hour" button, no record of what was missed. If those events mattered — a compliance sink, a downstream ticket sync, a billing hook — you're reconstructing them by hand from Jira's history and hoping you got the set right.
What you end up building: a durable queue in front of your receiver, so your infrastructure holds the events even when your service is down. Reasonable engineering, but it's real infrastructure you now own for the life of the integration.
Atlassian’s failed-webhook API (GET /rest/api/3/webhook/failed) sometimes gets suggested here, but it doesn’t help site admins: it’s scoped to the requesting Connect app, and a failure may stop being returned after 72 hours. It has no relation to webhooks configured under System → WebHooks.
Someone bulk-edits 300 issues. Someone drags an issue across a board and Jira emits several updates in a second. An automation rule touches every issue in a sprint.
Native webhooks fire per event, faithfully. Your receiver gets all of it. If the receiver is a Slack channel, a human is now getting a wall of near-identical notifications. If it's a rate-limited API, you're getting 429s and losing deliveries anyway.
What you end up building: debouncing or coalescing logic on the receiver, keyed by entity, with a time window. Not hard, but it's the third piece of infrastructure in this article and they all compound.
Native coverage is broad but not complete. Eight that come up regularly and don't exist as native webhook events:
"Notify the on-call channel when someone is @-mentioned" and "sync our component list to the service catalogue" both sound trivial and both run straight into this.
Issue Assigned, Issue Mentioned and Comment Mentioned as ordinary checkboxes, alongside the JQL filter.
What you end up building: polling. A scheduled job hitting the REST API on an interval, diffing state, inferring the event that the platform didn't tell you about. This is the worst of the workarounds — it's laggy, it burns API quota, and diffing logic is where subtle bugs live.
Native webhooks are event-driven only. There's no "fire this every weekday at 09:00" — so a daily digest, a nightly reconciliation ping, or a scheduled health check to a downstream system needs an external scheduler holding Jira credentials.
We built Webhooks Pro because those five workarounds kept showing up as the same five workarounds, rebuilt separately at every organisation, each one a small permanent operational tax.
The design goal was to move all of it inside Jira, so there's nothing to host:
{{issue.key}}-style placeholders. Custom headers and URL parameters too.Two ways to define the body: map Jira fields to keys, or write the JSON yourself.
It's a Forge app, so it runs on Atlassian infrastructure — no external service in the path.
Listing here if you want to look: Webhooks Pro on the Atlassian Marketplace
Should I just use native?
If your receiver accepts Jira's payload as-is and you'd notice quickly when it breaks, yes. Native is genuinely good at that job and there's no reason to add anything.
Doesn't Jira Automation already do webhooks?
It sends web requests, yes, and for simple cases it's a good answer. Where it gets awkward is volume-heavy integrations and diagnosis — you're inside the automation audit log rather than looking at a delivery-level record of what was sent and what came back.
Why no auto-retry?
Predictability. Auto-retry means a receiver having a bad minute gets hit three times as hard, and you can't tell from the receiver's logs how many times it was actually called. Manual replay keeps the delivery count honest and puts the decision with the person who can see why it failed.
Does this replace my queue?
No, and I'd be careful with anyone who says otherwise. If delivery is business-critical, the receiver should still be idempotent and durable. Logs and replay shorten the recovery, they don't remove the need for the receiver to be built properly.
If you've hit one of these walls, I'd genuinely like to hear which one and what you built around it — the workarounds people come up with are usually more interesting than the gap itself.
Denys Aleksieienko _UX Software_
2 comments