Skip to content

feat: add pagerduty-webhooks skill - #210

Merged
garethx merged 2 commits into
hookdeck:mainfrom
garethx:feat/pagerduty-webhooks
Oct 2, 2026
Merged

garethx merged 2 commits into
hookdeck:mainfrom
garethx:feat/pagerduty-webhooks

Conversation

@garethx

@garethx garethx commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Adds a pagerduty-webhooks skill for PagerDuty V3 webhook subscriptions — SKILL.md, three reference docs, and working Express / Next.js / FastAPI receivers with tests.

Scheme (and the two things a reviewer will want to check)

HMAC-SHA256 over the raw body, lowercase hex, in X-PagerDuty-Signature.

  1. The header can carry MORE than one signature, comma-separated, each v1=-prefixed, for zero-downtime secret rotation. All three examples accept a match against any v1= entry and ignore unknown-version entries rather than failing. Comparing the whole header string, or only the first entry, works right up until someone rotates the secret.
  2. There is no timestamp and no nonce, so there is deliberately no replay-window check. Replay protection is de-duplication on the documented X-Webhook-Id header. An added tolerance check here would be a bug, not a hardening.

Also: no handshake (the secret comes back in the create-subscription API response); 400 for a malformed header or empty body vs 403 for a mismatch, mirroring PagerDuty's Go client — both 4xx, which PagerDuty treats as permanent, so a forged request is never retried; fail-closed when the secret is unset.

Sources: the Verifying Signatures pseudo-algorithm and go-pagerduty/webhookv3/webhookv3.go, which is the only official verifier (neither @pagerduty/pdjs nor pdpyras ships one).

Identity

V3 subscriptions only. Not V1 extensions (EOL Oct 2022), not V2 extensions (end-of-support Oct 2022, messages[] payload, different event names like incident.trigger), and not the Events API v1/v2, which is inbound to PagerDuty. Hookdeck's sourceTypeSchemas.ts has no PAGERDUTY source type yet, so the variant was resolved from the docs rather than from Hookdeck's own source config.

All 30 event types come from the docs' Event Types table with their data.type values, including the naming traps: incident.service_updated (underscore) vs service.updated, incident.role.assigned covering unassignment, incident.annotated rather than incident.note.created. Every framework has a default branch — PagerDuty says more types may be added and also ships undocumented Early Access events.

Hedged on purpose

POST /webhook_subscriptions/{id}/ping and the pagey.ping event it delivers are confirmed verbatim against PagerDuty's OpenAPI schema (operationId: testWebhookSubscription), and the same schema confirms there is no customer-facing secret-rotate endpoint. But nothing documents whether the ping carries X-PagerDuty-Signature, so the skill says so instead of asserting it. pagey.ping is not subscribable, so it lands in the default branch.

Source IPs are the published per-region safelists, with the advice to fetch the JSON at runtime rather than hardcode — defence in depth, not verification.

Testing

  • validate-provider.sh pagerduty-webhooks — PASSED
  • Express: 41 passed · Next.js (Node 24): 41 passed · FastAPI (fresh venv): 43 passed

No live PagerDuty account was available, so the digest has not been checked against a real delivery.

🤖 Generated with Claude Code

garethx and others added 2 commits October 1, 2026 18:56
Adds the README row, providers.yaml entry (the research brief, verbatim)
and marketplace.json registration the generator staged but never wrote,
so validate-provider.sh passes.

Also softens six places that called the pagey.ping test delivery
"signed". POST /webhook_subscriptions/{id}/ping and the pagey.ping event
are both confirmed against PagerDuty's own OpenAPI schema, but neither
the docs nor the schema say the ping carries X-PagerDuty-Signature, so
the skill no longer asserts it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@garethx
garethx marked this pull request as ready for review October 2, 2026 14:47
@garethx
garethx merged commit d7761b1 into hookdeck:main Oct 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant