Guide to Opsgenie Webhooks: Features and Best Practices
Opsgenie webhooks send alert activity to the systems around your on-call process: an alert is created, someone acknowledges it, a note is added, the priority changes, it escalates or it closes. If you sync alerts to a ticketing tool, a status page or an incident timeline, the Webhook integration pushes each of those actions as it happens.
This guide covers how the Opsgenie Webhook integration maps alert actions to requests, what the payloads contain, how to authenticate requests Opsgenie doesn't sign, and the best practices for a production receiver. It starts with something you need to plan for: Opsgenie is being shut down.
Opsgenie's end of support
Atlassian is moving Opsgenie's capabilities into Jira Service Management. Opsgenie reached end of sale on June 4, 2025, and its end of support date is April 5, 2027. Atlassian says existing customers can keep using Opsgenie until then, after which it shuts down, any data that hasn't been moved is deleted, and remaining Opsgenie-based integrations stop working. Opsgenie also shuts down automatically 120 days after a customer's migration date if a site admin doesn't turn it off first.
If you're building a new Opsgenie webhook receiver, build it knowing it has a fixed lifetime. Keep the alert-handling logic separate from the Opsgenie-specific parsing, so you can put a Jira Service Management integration in front of the same logic when you migrate.
What are Opsgenie webhooks?
The Webhook integration sends an HTTP POST with a JSON body to a URL you choose when an alert action happens. You decide which actions post, using "post to url" mappings such as "If alert is created in Opsgenie, post to url". The payload carries the action plus a subset of the alert's fields, and you can choose to include the alert description and details.
Opsgenie doesn't sign webhook requests. The integration's only authentication setting is custom headers, which are added to every call. Put a secret in one and have your receiver compare it.
Opsgenie webhook features
| Feature | Details |
|---|---|
| Configuration | Settings > Integrations > Add integration > Webhook |
| Team scope | Optional Assignee team on the integration |
| Mappings | One "post to url" per alert action. Tag-added and custom-action mappings can be repeated with different tags or action names |
| Method | POST with a JSON body |
| Payload | action, an alert subset, source, integrationId, integrationName |
| Description and details | Optional, truncated to 1,000 characters, only for Create and custom actions |
| Authentication | Custom headers on the integration |
| Signature | None |
| Retries and timeout | Not documented |
| Lifecycle | End of sale June 4, 2025. End of support April 5, 2027 |
Common events
The action field names what happened. Opsgenie documents 16 standard actions:
action | Fires when | Extra fields |
|---|---|---|
Create | An alert is created | alert.teams, alert.recipients |
Acknowledge | An alert is acknowledged | |
UnAcknowledge | An acknowledgement is removed | |
AddNote | A note is added | alert.note |
AddTags | Tags are added | alert.addedTags |
RemoveTags | Tags are removed | alert.removedTags |
AddTeam | A team is added | alert.team |
AddRecipient | A recipient is added | alert.recipient |
AssignOwnership | An owner is assigned | alert.owner |
TakeOwnership | A user takes ownership | |
Escalate | An alert is escalated | escalationId, escalationName, escalationNotify, escalationTime, repeatCount |
UpdatePriority | The priority changes | alert.priority, alert.oldPriority |
UpdateMessage | The message changes | alert.message |
UpdateDescription | The description changes | alert.description |
Close | An alert is closed | |
Delete | An alert is deleted |
Custom alert actions send their own name as action, for example TestAction, so your router will see values outside this list if your team uses them.
Here is Opsgenie's example for a created alert:
{
"source": { "name": "web", "type": "API" },
"alert": {
"alertId": "052652ac-5d1c-464a-812a-7dd18bbfba8c",
"alias": "aliastest",
"tinyId": "23",
"message": " test alert",
"tags": ["tag1", "tag2"],
"teams": ["team1", "team2"],
"recipients": ["recipient1", "recipient2"],
"username": "fili@ifountain.com",
"userId": "daed1180-0ce8-438b-8f8e-57e1a5920a2d",
"source": "fili@ifountain.com",
"entity": "",
"createdAt": 1420452191104,
"updatedAt": 1420452193166002000
},
"action": "Create",
"integrationId": "37c8f316-17c6-49d7-899b-9c7e540c048d",
"integrationName": "Integration1"
}
Note the units: createdAt is in milliseconds, but updatedAt has nanosecond precision. A 19-digit nanosecond value is larger than JavaScript can represent exactly as a number, so don't use it as an exact key without care. Escalate is shaped differently from the rest: its alert object holds only alertId, and the escalation details sit at the top level.
See Opsgenie webhook payloads in action. Inspect and replay sample Opsgenie webhook payloads in Hookdeck Inspect, with no account or setup required.
Setting up Opsgenie webhooks
Generate a long random secret first (openssl rand -hex 32 works) and store it in your app's environment.
- In Opsgenie, go to Settings > Integrations and select Add integration.
- Search for and select Webhook.
- Name the integration and, optionally, choose an Assignee team to limit it to that team's alerts. Select Continue.
- Enter your HTTPS endpoint as the Webhook URL.
- Add a custom header for authentication, for example
X-Webhook-Secretwith your secret, orAuthorizationwithBearer <secret>. - Tick the boxes to send the alert description and details if you need them. They're only sent for
Createand custom actions. - Under the post-to-URL section, add a mapping for each alert action you want, for example "If alert is created in Opsgenie, post to url".
- Select Turn on integration. Mappings only work once the integration is on.
Each standard action can have only one "post to url" mapping per integration. Opsgenie raises an error if you add a second, except for "a tag is added to the alert" and "a custom action is executed on alert", which can have several mappings as long as the tags or custom action names differ.
For local development, use the Hookdeck CLI: hookdeck listen 3000 opsgenie --path /webhooks/opsgenie gives you a public HTTPS URL that forwards to your local server, plus a web UI for inspecting and replaying deliveries, with no account required.
With Hookdeck. Create an Opsgenie source in Hookdeck, enter the Header Name and Header Value exactly as you set them on the integration, including any Bearer prefix, and use the source URL as the Webhook URL.
Securing Opsgenie webhooks
Compare your custom header with the stored value. Look it up case-insensitively, compare the whole value in constant time, and check lengths first, because crypto.timingSafeEqual throws on buffers of different lengths.
const crypto = require('crypto');
const express = require('express');
const app = express();
function safeEqual(a, b) {
const x = Buffer.from(String(a), 'utf8');
const y = Buffer.from(String(b), 'utf8');
return x.length === y.length && crypto.timingSafeEqual(x, y);
}
function verifyOpsgenieRequest(headers) {
const secret = process.env.OPSGENIE_WEBHOOK_SECRET;
if (!secret) return false; // fail closed when unconfigured
const name = (process.env.OPSGENIE_WEBHOOK_HEADER || 'X-Webhook-Secret').toLowerCase();
const received = headers[name];
return typeof received === 'string' && safeEqual(received, secret);
}
app.post('/webhooks/opsgenie', express.raw({ type: '*/*' }), (req, res) => {
if (!verifyOpsgenieRequest(req.headers)) {
return res.sendStatus(401);
}
let payload;
try {
payload = JSON.parse(req.body.toString('utf8'));
} catch {
return res.sendStatus(400);
}
res.sendStatus(200);
const alertId = payload.alert && payload.alert.alertId;
switch (payload.action) {
case 'Create':
// open a ticket keyed on alertId
break;
case 'Acknowledge':
case 'Close':
// update the ticket's state
break;
default:
// other standard or custom actions
break;
}
});
The same check in Python:
import hmac
import os
def verify_opsgenie_request(headers) -> bool:
secret = os.environ.get("OPSGENIE_WEBHOOK_SECRET")
if not secret:
return False
name = os.environ.get("OPSGENIE_WEBHOOK_HEADER", "X-Webhook-Secret")
received = headers.get(name) # case-insensitive in Starlette and Flask
if not received:
return False
return hmac.compare_digest(received.encode("utf-8"), secret.encode("utf-8"))
A static header authenticates the sender, not the body, and it gives no replay protection: there's no signature or timestamp, so a captured request can be resent. Serve the endpoint over HTTPS, keep the secret out of logs, and rotate it on the integration if it leaks. Opsgenie also publishes a list of outbound static IPs that you can allow at a firewall as a second layer.
Make Opsgenie webhooks production-ready. Hookdeck Event Gateway checks your custom header on every request, stores each alert action durably, and retries delivery to your service, so a receiver outage doesn't leave your ticketing tool out of step with on-call.
Opsgenie webhook limitations and pain points
A product with an end date
The Problem: Any Opsgenie webhook integration you build stops working when Opsgenie shuts down.
Why It Happens: Opsgenie's end of support date is April 5, 2027, and Atlassian is moving customers to Jira Service Management. Integrations left in Opsgenie stop working when it's turned off, which can happen earlier for a customer who has migrated.
Workarounds:
- Keep alert-handling logic independent of Opsgenie's payload format.
- Plan the replacement integration in Jira Service Management alongside your migration.
How Hookdeck Can Help: Hookdeck sits between the sender and your service. When you move to a new alerting source, you can point it at a new Hookdeck source and use transformations to reshape its payloads, keeping one stable format for your handler during the switch.
No documented retries
The Problem: If your endpoint is down when an alert is acknowledged or closed, you may never get that update.
Why It Happens: The Webhook integration page documents no retry policy, timeout or expected response.
Workarounds:
- Keep the receiver fast and available, and return
200quickly. - Reconcile open alerts from the Opsgenie API after an outage.
How Hookdeck Can Help: Hookdeck accepts each request as it arrives, stores it, and delivers to your service with automatic retries on a schedule you control. Issues alert you when deliveries fail, and you can replay any stored alert action.
No signature on the request
The Problem: A forged request with the right header value looks identical to a real alert action.
Why It Happens: Custom headers are the only authentication the integration offers.
Workarounds:
- Use a long random header value and compare it in constant time.
- Look up the alert through the Opsgenie API before taking a destructive action.
How Hookdeck Can Help: Hookdeck's Opsgenie source compares the header you name against the exact value you enter. A request without a matching header still gets a 200 response, but Hookdeck marks it as failed verification and creates no event, so it never reaches your destination. Every request is stored with its headers and body.
Ordering and missing context
The Problem: Actions for one alert can arrive close together, and most of them don't carry the description or details.
Why It Happens: Each action is its own request. Description and details are only sent for Create and custom actions, and are cut to 1,000 characters.
Workarounds:
- Key every record on
alert.alertIdand apply actions as state changes. - Fetch the full alert from the API when you need the description or details.
How Hookdeck Can Help: Filters can route actions by action to different destinations, for example sending Create and Close to your ticketing integration and everything else to an audit log.
Best practices
Map only the actions you need
Each mapping sends traffic your receiver has to handle. Start with Create, Acknowledge and Close, and add others as you use them.
Key on alertId
Use alert.alertId to tie actions together. tinyId and alias are handy for display, but alertId is the stable identifier.
Handle custom and unknown actions
Custom actions arrive with their own names. Acknowledge anything you don't recognise with a 200 and log it, rather than failing.
Acknowledge fast and make handlers idempotent
Return 200 once the header checks out, process asynchronously, and build a deduplication key from alertId, action and updatedAt stored as a string. See why to process webhooks asynchronously and our guide to webhook idempotency.
Conclusion
The Opsgenie Webhook integration posts unsigned JSON for each mapped alert action, with the action name in action and a subset of the alert in alert. Authenticate it with a custom header compared in constant time over HTTPS, key your records on alertId, and watch the mixed timestamp units. Above all, plan for April 5, 2027, when Opsgenie's support ends and the integration stops.
Hookdeck Event Gateway checks the header, stores every alert action and retries delivery to your service, and gives you one place to reshape payloads when you move to a new alerting source.
Get started with Hookdeck for free and handle Opsgenie webhooks reliably in minutes.