Agent skill
Opsgenie Webhooks Skill
Receive and authenticate Opsgenie webhooks. Use when setting up an Opsgenie Webhook integration endpoint, checking the secret custom header, debugging 401s, or handling alert actions like Create, Acknowledge, Close, AddNote and Escalate.
Install this skill
npx skills add hookdeck/webhook-skills --skill opsgenie-webhooks
Opsgenie (Atlassian incident alerting) can post a JSON webhook to your URL whenever an alert action happens: an alert is created, acknowledged, closed, escalated and so on. Webhooks are not signed. You add a secret custom header to the Webhook integration, and your endpoint authenticates each request by comparing that header with the value you stored.
Opsgenie is end-of-sale and Atlassian support ends in April 2027. Customers are being moved to Jira Service Management and Compass. Existing Webhook integrations keep working until then; plan to re-point alert automation at the replacement product.
When to Use This Skill
- How do I receive Opsgenie webhooks?
- How do I authenticate an Opsgenie Webhook integration? (No signature: use a secret custom header)
- How do I handle
Create,Acknowledge,CloseorEscalatealert actions? - How do I handle a custom alert action name?
- Why does my Opsgenie webhook endpoint return 401?
Verification (core)
const crypto = require('crypto');
// Lengths first: timingSafeEqual throws on buffers of different sizes.
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,
headerName = process.env.OPSGENIE_WEBHOOK_HEADER || 'Authorization',
secret = process.env.OPSGENIE_WEBHOOK_SECRET) {
if (!secret) return false; // never accept when unconfigured
const received = headers[headerName.toLowerCase()]; // Node lowercases header names
return typeof received === 'string' && received !== '' && safeEqual(received, secret);
}
- The header name is whatever you typed as the custom header on the Webhook integration. Read it from
OPSGENIE_WEBHOOK_HEADER(defaultAuthorization) and look it up case-insensitively. - Compare the whole value with
OPSGENIE_WEBHOOK_SECRET, exactly as typed in Opsgenie. If you enteredBearer abc123, the secret isBearer abc123. Don't strip or parse aBearerprefix. - Return
401for a missing header or a mismatch,400for a body that isn't a JSON object,200once handled. - Read the body raw (
express.raw({ type: '*/*' })) and authenticate before parsing it. - Python:
hmac.compare_. Always pass bytes;digest(a.encode(), b.encode()) strarguments raiseTypeErroron non-ASCII.
What this does and doesn't give you. A static shared credential authenticates the sender, not the body, and gives no replay protection (there is no signature and no timestamp): anyone who captures one request can resend it. Use HTTPS, make handlers idempotent, and rotate the credential if it leaks.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Alert Actions
The payload has an action field, an alert object and usually a source object, plus integrationId and integrationName.
action | Sent When | Extra alert fields |
|---|---|---|
Create | An alert is created | teams, recipients |
Acknowledge | An alert is acknowledged | |
UnAcknowledge | An acknowledgement is removed | |
AddNote | A note is added | note |
AddTags | Tags are added | addedTags |
RemoveTags | Tags are removed | removedTags |
Close | An alert is closed | |
AssignOwnership | An owner is assigned | owner |
TakeOwnership | A user takes ownership | |
Delete | An alert is deleted | |
Escalate | An alert is escalated | top-level escalationName, escalationNotify; alert has only alertId |
UpdatePriority | Priority changes | priority, oldPriority |
UpdateDescription | Description changes | description |
UpdateMessage | Message changes | message |
AddTeam | A team is added | team |
AddRecipient | A recipient is added | recipient |
| your own name | A custom action runs | Sent as action, e.g. TestAction |
Environment Variables
OPSGENIE_WEBHOOK_HEADER=Authorization # name of the custom header you added in Opsgenie
OPSGENIE_WEBHOOK_SECRET=your-secret # its exact, whole value (including any "Bearer " prefix)
Local Development
Opsgenie can't reach localhost. Tunnel with the Hookdeck CLI (no account required):
npx hookdeck-cli listen 3000 opsgenie --path /webhooks/opsgenie
Use the printed URL as the webhook URL in Opsgenie.
Resources
- references/overview.md - What Opsgenie webhooks are, actions and payload shape
- references/setup.md - Add the Webhook integration and the secret header
- references/verification.md - Header check details, limits, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests