Appearance
Webhooks service
/webhooks lets you subscribe HTTPS endpoints to device and step activity, so your systems learn about changes as they happen instead of polling devices and trails. It is the customer-facing counterpart to the internal callbacks service: callbacks drive Pantahub's own derived state, webhooks drive yours.
The service consumes the change stream behind the API, derives typed events from it, and POSTs each one to every matching subscription with an HMAC-SHA256 signature and retries.
For the end-to-end walkthrough — creating a subscription in the Hub, verifying a delivery, what to return — see the Webhooks guide.
Calls need a JWT from auth carrying one of the api, api.readonly, webhooks, webhooks.readonly or webhooks.write scopes. Read operations accept the read scopes; anything that mutates a subscription needs a write scope.
sh
TOKEN=$(curl -s -X POST https://api.pantahub.com/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"<user>","password":"<pass>"}' | jq -r .token)Event catalog
sh
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/event-typesReturns every event type with a human description — the same list the Hub renders when you create a subscription:
device.created device.updated device.deleted
device.public.toggled device.device_meta.updated device.user_meta.updated
step.created step.progress.changed step.status.changedCreating a subscription
sh
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
https://api.pantahub.com/webhooks/ \
-d '{
"nick": "production-fleet",
"url": "https://example.com/hooks/pantahub",
"event_types": ["step.status.changed", "device.created"],
"enabled": true
}'The response includes the generated signing secret. It is returned only on creation and on rotation — store it then, or rotate to get a new one.
Optional fields narrow what you receive: devices (a list of device PRNs), user_meta_keys and device_meta_keys (limit metadata events to changes touching those keys), custom_headers (sent with every delivery), and retry_policy.
Managing subscriptions
sh
# list
curl -s -H "Authorization: Bearer $TOKEN" https://api.pantahub.com/webhooks/
# one subscription
curl -s -H "Authorization: Bearer $TOKEN" https://api.pantahub.com/webhooks/<id>
# pause without deleting
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
https://api.pantahub.com/webhooks/<id> -d '{"enabled": false}'
# delete
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>PUT replaces a subscription wholesale, PATCH merges the fields you send. A deleted subscription stops receiving events immediately.
Testing and rotation
sh
# send a synthetic delivery through the full signing + retry path
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>/test
# rotate the signing secret; deliveries are signed with both during overlap
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>/rotate-secretRotation keeps the previous secret as a secondary and signs every delivery with both, so receivers that check every v1, entry in the Webhook-Signature header keep working while you roll the new value out.
Delivery history
sh
# every attempt for one subscription (filter with ?status=failed)
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>/deliveries
# one attempt, including the recorded request and response
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>/deliveries/<did>
# resend a single attempt
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/<id>/deliveries/<did>/replayEach row records the attempt number, status, the HTTP response code and duration, and the scheduling timestamps — enough to tell a receiver that timed out from one that rejected the payload.
Events
The /webhooks/events* family is the account-wide log: every event derived for you, whether or not a subscription matched.
sh
# recent events (?type=, ?resource_prn=, ?since=, ?until=, ?limit=, ?skip=)
curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.pantahub.com/webhooks/events?limit=50"
# one event, including its full payload
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/events/<eid>
# every delivery of that event, across all subscriptions
curl -s -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/events/<eid>/deliveries
# fan a fresh attempt out to every matching subscription
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
https://api.pantahub.com/webhooks/events/<eid>/redeliverFetching an event by id doubles as an authenticity check: events are scoped to the caller's owner, so an id you did not receive — or one belonging to another account — returns 404. That makes GET /webhooks/events/{eid} a useful second line of defence before acting on a high-value delivery.
Delivery semantics
Deliveries are at-least-once and unordered. A 2xx completes an attempt; 408, 425, 429 and 5xx are retried with exponential backoff (8 attempts from 30 s by default, doubling); any other 4xx is treated as permanent and dead-lettered without retry. Each attempt must finish within 10 seconds.
Receivers should dedupe on the event id, which is stable across retries, rather than request_id, which is per attempt.
Endpoint summary
| Endpoint | Purpose |
|---|---|
GET /webhooks/event-types | Catalog of event types |
GET /webhooks/ | List subscriptions |
POST /webhooks/ | Create a subscription |
GET /webhooks/{id} | Read one subscription |
PUT / PATCH /webhooks/{id} | Replace / merge a subscription |
DELETE /webhooks/{id} | Delete a subscription |
POST /webhooks/{id}/rotate-secret | Rotate the signing secret |
POST /webhooks/{id}/test | Send a synthetic delivery |
GET /webhooks/{id}/deliveries | Delivery log for a subscription |
GET /webhooks/{id}/deliveries/{did} | One delivery attempt |
POST /webhooks/{id}/deliveries/{did}/replay | Resend one attempt |
GET /webhooks/events | Account-wide event log |
GET /webhooks/events/{eid} | One event with payload |
GET /webhooks/events/{eid}/deliveries | Deliveries of an event |
POST /webhooks/events/{eid}/redeliver | Redeliver to all matching subs |