How the webhook URL works. It is a public address that records whatever is sent to it and
answers 200. An inbox keeps the 50 most recent requests, accepts bodies up to 256 KB, and is
deleted 24 hours after it was created — or sooner if you press Delete URL or our server
restarts, because requests are held in memory and never written to disk.
Anyone who has the URL can read what it received. Use sandbox and test-mode accounts, do not route production traffic or customer data through it, and delete it when you are done. Privacy details.
What is a Jira webhook?
A Jira webhook is an HTTP POST that Jira sends to a URL when an event you selected occurs: an issue is created, updated or deleted, a comment is added, a sprint starts, a version is released. The event name is in the body as webhookEvent, for instance jira:issue_updated, with a finer-grained issue_event_type_name beside it.
Webhooks can be registered by an administrator in Jira's settings or by an app through the REST API, and either kind can be narrowed with a JQL filter so that only matching issues fire. Issue events include the full issue representation, which makes the payloads large; an update also includes a changelog listing each field that changed with its old and new value.
What a Jira webhook request looks like
The request line and headers as they reach your server, followed by the body. Ids, tokens and the signature are placeholders.
POST /your/webhook/path HTTP/1.1
Host: your-server.example
X-Atlassian-Webhook-Identifier: 3f1c9b7e-2d4a-4c8f-9e0b-6a5d1f2c3b4e
X-Hub-Signature: sha256=a4771c39fbe90f317c7824e83ddef3caae9cb3d976c214ace1f2937e133263c9
X-Atlassian-Webhook-Retry: 1
X-Atlassian-Webhook-Flow: Primary
Content-Type: application/json; charset=UTF-8
User-Agent: Atlassian Webhook HTTP Client
{
"timestamp": 1767225600000,
"webhookEvent": "jira:issue_updated",
"issue_event_type_name": "issue_generic",
"user": {
"accountId": "5b10a2844c20165700ede21g",
"displayName": "Ada Lovelace",
"accountType": "atlassian"
},
"issue": {
"id": "10042",
"self": "https://your-site.atlassian.net/rest/api/2/issue/10042",
"key": "OPS-17",
"fields": {
"summary": "Webhook worker drops retries",
"issuetype": {
"id": "10004",
"name": "Bug"
},
"project": {
"id": "10000",
"key": "OPS",
"name": "Operations"
},
"status": {
"id": "10001",
"name": "In Progress"
},
"priority": {
"id": "2",
"name": "High"
},
"assignee": {
"accountId": "5b10a2844c20165700ede21g",
"displayName": "Ada Lovelace"
},
"customfield_10016": 3,
"updated": "2026-01-01T12:00:00.000+0000"
}
},
"changelog": {
"id": "10310",
"items": [
{
"field": "status",
"fieldtype": "jira",
"from": "10000",
"fromString": "To Do",
"to": "10001",
"toString": "In Progress"
}
]
}
}
This is heavily trimmed; a real issue carries every field on the screen and more. Custom fields appear under opaque keys such as customfield_10016, and the key for the same field differs between Jira sites. People are identified by accountId; email addresses are usually absent. The changelog exists only on updates, and its from and to are ids while fromString and toString are the readable names.
Headers Jira sends
| Header | Example | What it is |
|---|---|---|
X-Atlassian-Webhook-Identifier | 3f1c9b7e-2d4a-4c8f-9e0b-6a5d1f2c3b4e | Unique id of this webhook delivery. It is the same on every retry. |
X-Hub-Signature | sha256=a4771c39fbe90f317c7824e83ddef3caae9c… | HMAC-SHA256 of the body, hex. Present only when the webhook was given a secret. |
X-Atlassian-Webhook-Retry | 1 | Present on a retry: how many retries have been made so far. |
X-Atlassian-Webhook-Flow | Primary | Whether the event went through the normal delivery flow or a secondary one used for very large or delayed events. |
Content-Type | application/json; charset=UTF-8 | The body is JSON. |
User-Agent | Atlassian Webhook HTTP Client | Identifies the sender. |
Header names are case-insensitive. Your framework may show them lower-cased, and HTTP/2 always does.
How Jira signs a webhook
A webhook created in Jira Cloud's settings can be given a secret. When it has one, Jira computes an HMAC-SHA256 of the request body with that secret and sends sha256= plus the hex digest in the X-Hub-Signature header. Without a secret the request carries no proof of origin, and many older Jira integrations therefore relied on an unguessable URL alone.
Webhooks registered by Connect or OAuth apps are authenticated differently, with a signed JWT in the Authorization header rather than a body HMAC. Compute it over the raw request body exactly as received — before any JSON parsing — and compare with a constant-time function.
const crypto = require('crypto');
// rawBody: Buffer or string of the body exactly as received
function verifyJira(rawBody, header, secret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(header || '');
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Retries, ordering and large payloads
Jira Cloud retries a delivery that fails to connect or that is answered with certain statuses — timeouts, 429 and 5xx among them — up to five times with a randomised, growing delay, per Atlassian's documentation at the time of writing. Each retry repeats X-Atlassian-Webhook-Identifier, which is the value to de-duplicate on. Other 4xx replies are final.
Events for the same issue are not guaranteed to arrive in the order they happened, especially when a bulk change fires hundreds at once. Compare the body's timestamp, or re-read the issue through the REST API using issue.self, before overwriting newer data with older.
Catch a real Jira webhook
- Press Create webhook URL at the top of this page and copy the address.
- As a Jira administrator, open Settings → System → WebHooks and create a webhook. A free test site is the safe place to do this.
- Paste the address as the URL, add a secret if you want to see the signature header, and tick events such as issue created and updated.
- Optionally narrow it with a JQL filter, for example a single test project, then save.
- Edit an issue in that project and read the delivery in the inbox above.
Issue payloads contain summaries, descriptions, comments and names. Point a webhook at a public inbox only from a site that holds test data.
To run a caught request against your own code, select it and press Open in API Tester: the method, headers and body are loaded into the request console, where you enter your server's public URL and send it. A body you edit will no longer match its signature — that is the signature doing its job.
Things that catch people out
- Custom field keys are per-site. Look the key up through the fields API instead of hard-coding
customfield_10016. - The JQL filter is evaluated after the change. An edit that moves an issue out of the filter's scope may not fire at all.
- Jira Data Center differs. The self-hosted product has its own webhook settings, retry behaviour and authentication options.
api-tester.com is independent and is not affiliated with Jira. Providers change header names, limits and retry schedules; treat the official Jira documentation as the source of truth.
Related examples and tools
Mailgun Webhook Example
Mailgun puts its signature inside the JSON body instead of in a header, and that signature covers a timestamp and a token rather than the event itself.
Typeform Webhook Example
A Typeform webhook sends one form submission: the questions as they were defined and the answers as they were given, in two separate arrays you have to join yourself.
Calendly Webhook Example
Calendly webhooks are created through the API rather than a settings page, and they describe everything by URI.
Linear Webhook Example
A Linear webhook reports a change to one entity — an issue, a comment, a project — and, on updates, tells you the previous values of whatever changed.
Clerk Webhook Example
Clerk delivers its webhooks through Svix, so the three svix- headers and their signing scheme are shared with every other service that uses the same infrastructure.
JSON Formatter
Fold and search a large issue payload to find the field you need.
Curl POST JSON
Send a JSON body like this one from a terminal.
Webhook Tester
The inbox on its own page, plus a guide to signatures, retries and idempotent handlers.
All Webhook Examples
30 providers side by side: content type, signature scheme and retry behaviour.
Other webhooks signed with an HMAC of the body
References
- Official Jira documentation — The provider's own guide to the requests described on this page.
- Jira Cloud REST API: webhooks — Registering and refreshing webhooks over the API.
- RFC 2104: HMAC — The keyed-hash construction this signature is built on.
- Node.js: crypto.timingSafeEqual() — The constant-time comparison used in the code on this page.
These links leave api-tester.com, which is independent of the companies and projects they point to.
Jira webhook FAQ
What does a Jira webhook payload look like?
A JSON object with timestamp, webhookEvent, a user, and for issue events an issue object containing id, key, self and all fields. Update events add a changelog listing each changed field with its old and new value.
How do I verify a Jira webhook?
Set a secret on the webhook. Jira then sends X-Hub-Signature containing sha256= and the hex HMAC-SHA256 of the request body, which you recompute over the raw body and compare in constant time.
Does Jira retry failed webhooks?
Jira Cloud retries connection failures, timeouts, 429 and 5xx responses up to five times according to Atlassian's documentation at the time of writing. Retries carry the same X-Atlassian-Webhook-Identifier.
How do I find what changed in a Jira issue webhook?
Read changelog.items on a jira:issue_updated event. Each item names the field and gives from and to ids plus fromString and toString display values.
Can I filter which issues trigger a Jira webhook?
Yes. A webhook can have a JQL filter, so only events for issues matching the query are sent.