Webhooks
9 endpoints in this family.
List your webhook subscriptions
GET/api/v1/webhooks
Returns where Nodium calls you and for which events, plus the list of every event name you can subscribe to. Secrets are never returned.
Response
The subscriptions, the event catalogue and the latest deliveries.
data.eventsstring[]Every event name you can subscribe to.
data.subscriptionsWebhookSubscription[]Your subscriptions, newest first.
data.deliveriesWebhookDelivery[]The 50 most recent deliveries. The full log is
GET /webhooks/deliveries.
Refusals
- 404
not_foundThe key acts on "My company" but is pinned to it: those subscriptions also carry the events of every client, so they need a key that is not pinned.
curl https://nodium.io/api/v1/webhooks \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "events": [ "…" ], "subscriptions": [ {} ], "deliveries": [ {} ] }}Subscribe to events
POST/api/v1/webhooks
Registers an HTTPS address that Nodium calls when something happens. Without this your software has to poll, which is slower and heavier for both of us.
The response carries the signing secret once and never again: store it now. Each call is signed with it, and is retried up to six times with growing delays (1 min, 5 min, 30 min, 2 h, 12 h).
Body
urlstringrequiredWhere to call. Must start with https://.
eventsstring[]requiredWhich events to receive.
*means all of them.channelIdsstring[]Only receive the events of these channels (numbers). Empty or absent: all channels. An event that belongs to no channel (a template status, a consent change) is not delivered to a limited subscription.
labelstringA name for you, shown in Nodium.
Response
The subscription id and its signing secret — shown only here.
data.idstringThe subscription id.
data.secretstringThe signing secret,
whsec_…. Shown only here.
Refusals
- 404
not_foundThe key acts on "My company" but is pinned to it: that subscription also carries the events of every client, so it needs a key that is not pinned. - 422
webhook_url_not_httpsThe address must start with https://. - 422
invalid_requestNo event, an unknown event name, or a channel outside this client (on "My company": outside your account).
curl -X POST https://nodium.io/api/v1/webhooks \ -H "Authorization: Bearer $NODIUM_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "…", "events": [ "…" ] }'{ "data": { "id": "…", "secret": "…" }}Unsubscribe
DEL/api/v1/webhooks/{id}
Removes the subscription. Nothing more is delivered to that address.
Path parameters
idstringThe subscription id.
Response
Confirmation that it is gone.
data.okbooleanAlways
true.
Refusals
- 404
not_foundNo such subscription, or not one this key can reach (on "My company", the key must not be pinned).
curl -X DELETE https://nodium.io/api/v1/webhooks/<id> \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "ok": true }}Get a subscription
GET/api/v1/webhooks/{id}
One webhook subscription: where Nodium calls you, for which events and numbers, and how its last deliveries went. The secret is never returned.
Path parameters
idstringThe subscription id.
Response
The subscription.
data.subscriptionWebhookSubscription
Refusals
- 404
not_foundNo such subscription, or not one this key can reach (on "My company", the key must not be pinned).
curl https://nodium.io/api/v1/webhooks/<id> \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "subscription": { "id": "…", "url": "…", "events": [], "channelIds": [], "label": "…", "isActive": true, "lastDeliveredAt": "…", "lastError": "…", "previousSecretValidUntil": "…", "createdAt": "…" } }}Change a subscription
PATCH/api/v1/webhooks/{id}
Moves the address, changes the events, renames, or pauses the subscription. Send only the fields you change. The secret does not change — rotate it with POST /webhooks/{id}/rotate-secret.
Path parameters
idstringThe subscription id.
Body
urlstringA new https address.
eventsstring[]The events to receive from now on.
*means all of them.labelstringA name for you, shown in Nodium.
channelIdsstring[]Limit the subscription to the events of these channels (numbers); an empty list means all channels.
isActivebooleanFalse pauses delivery: events keep queuing and are sent, in order, when set back to true. Nodium also pauses a subscription by itself after 50 consecutive failed attempts with nothing delivered for 24 h (see
disabledReason).
Response
The subscription, updated.
data.idstringThe subscription id.
data.urlstringThe https address called.
data.eventsstring[]The events delivered;
*means all.data.channelIdsstring[]The channels (numbers) whose events are delivered; empty means all channels.
data.labelstringIts name.
data.isActivebooleanA paused subscription receives nothing.
data.lastDeliveredAtstringThe last successful call, ISO 8601, or
null.data.lastErrorstringWhat went wrong last time, or
null.data.previousSecretValidUntilstringDuring a rotation: until when the old secret still signs.
nullotherwise.data.createdAtstringISO 8601.
Refusals
- 404
not_foundNo such subscription, or not one this key can reach (on "My company", the key must not be pinned). - 422
webhook_url_not_httpsThe address must start with https://. - 422
invalid_requestNothing to change, an unknown event, or a field of the wrong type.
curl -X PATCH https://nodium.io/api/v1/webhooks/<id> \ -H "Authorization: Bearer $NODIUM_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "…", "events": [ "…" ] }'{ "data": { "id": "…", "url": "…", "events": [ "…" ], "channelIds": [ "…" ], "label": "…", "isActive": true, "lastDeliveredAt": "…", "lastError": "…", "previousSecretValidUntil": "…", "createdAt": "…" }}Rotate the signing secret
POST/api/v1/webhooks/{id}/rotate-secret
Issues a new signing secret, returned once. For the next 24 hours every call carries two signatures — v1= with the new secret, then v1= with the old one — so you can deploy the new secret without missing a call. Accept a call when any v1 matches.
Rotating twice in a row forgets the oldest secret straight away.
Path parameters
idstringThe subscription id.
Response
The new secret, and until when the old one still signs.
data.secretstringThe new signing secret,
whsec_…. Shown only here.data.previousValidUntilstringISO date until which the old secret still signs.
Refusals
- 404
not_foundNo such subscription, or not one this key can reach (on "My company", the key must not be pinned).
curl -X POST https://nodium.io/api/v1/webhooks/<id>/rotate-secret \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "secret": "…", "previousValidUntil": "…" }}Send a test call
POST/api/v1/webhooks/{id}/test
Fires one signed message.received call at your address right now (the sample from the event catalogue, with data.test set to true) and reports what came back: status code, round trip, and the error if there was one. Use it to prove your endpoint and your signature check before going live.
Path parameters
idstringThe subscription id.
Response
What your endpoint answered: status, duration, and any error.
data.okbooleanWhether it answered 2xx.
data.statusintegerThe HTTP status, or
nullwhen unreachable.data.msintegerThe round trip.
data.errorstringWhat went wrong, or
null.
Refusals
- 404
not_foundNo such subscription, or not one this key can reach (on "My company", the key must not be pinned).
curl -X POST https://nodium.io/api/v1/webhooks/<id>/test \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "ok": true, "status": 0, "ms": 0, "error": "…" }}List deliveries
GET/api/v1/webhooks/deliveries
Every call Nodium made — or is about to make — to your addresses: which event, how many attempts, what your server answered, and when the next attempt is due. Newest first.
This is what settles "we never received it": a failed delivery with lastError tells you what your endpoint said; no delivery at all means the event did not happen.
Query parameters
subscriptionIdstringOnly this subscription.
statusstringOnly deliveries in this state.
pendingdeliveredfailedeventstringOnly this event, e.g.
message.received.limitintegerPage size, 1 to 100. Default 50.
cursorstringThe
nextCursorof the previous page.
Response
A page of deliveries, newest first.
data.itemsWebhookDelivery[]The deliveries.
data.nextCursorstringPass it as
cursorfor the next page;nullat the end.data.hasMorebooleanWhether another page exists.
Refusals
- 404
not_foundThe key acts on "My company" but is pinned to it: those deliveries also carry the events of every client, so they need a key that is not pinned.
curl https://nodium.io/api/v1/webhooks/deliveries \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "items": [ {} ], "nextCursor": "…", "hasMore": true }}Redeliver an event
POST/api/v1/webhooks/deliveries/{id}/redeliver
Queues the same event again for the same subscription — typically after your endpoint was down and the delivery ended failed. It goes out within a minute, with fresh retries.
The payload is identical, including its id: if you already processed it, your deduplication on id will skip it.
Path parameters
idstringThe delivery id.
Response
The new delivery, pending.
data.idstringThe delivery id, also sent as
X-Nodium-Delivery.data.subscriptionIdstringThe subscription.
data.eventstringThe event name.
data.eventIdstringThe event's own id (
evt_…), the same across redeliveries: deduplicate on it.data.statusstringfailedafter six attempts.pendingdeliveredfaileddata.attemptsintegerAttempts so far.
data.responseStatusintegerThe HTTP status your server answered, or
null.data.lastErrorstringWhat went wrong, or
null.data.nextAttemptAtstringWhen the next attempt is due, for a pending delivery.
data.createdAtstringISO 8601.
data.deliveredAtstringISO 8601, or
null.
Refusals
- 404
not_foundNo such delivery in this workspace, not one this key can reach (on "My company", the key must not be pinned), its subscription is paused or gone, or its payload was already erased by content retention.
curl -X POST https://nodium.io/api/v1/webhooks/deliveries/<id>/redeliver \ -H "Authorization: Bearer $NODIUM_KEY"{ "data": { "id": "…", "subscriptionId": "…", "event": "…", "eventId": "…", "status": "pending", "attempts": 0, "responseStatus": 0, "lastError": "…", "nextAttemptAt": "…", "createdAt": "…", "deliveredAt": "…" }}