Skip to main content

V3 webhook notifications API

Dashboard only

These routes back the dashboard's Notifications › Webhook page (https://dashboard.blockwyre.com, sandbox https://dashboard-sandbox.blockwyre.com). The admin.blockwyre.com and admin-sandbox.blockwyre.com hosts are BlockWyre's staff consoles, not the dashboard. These routes do not accept API keys: an integration manages its targets through the Webhook Targets API.

Tenant-admin management of outbound webhook endpoints lives under /v3/notifications/webhooks. It is open to every workspace, and it manages the same endpoints as the V2 targets API: an endpoint created or deleted through either shows on the other.

These routes serve the dashboard only: a workspace member signed in to the dashboard, with a role that grants the matching webhook permission (view, create, update, delete, enable, view deliveries, resend). API keys cannot call them: a request signed with an API key, or made with a customer session, is answered 401 with the message unauthorized; a member whose role lacks the permission, 403 with forbidden. To manage targets with an API key, use the Webhook Targets API (/api/v2/webhooks/targets) with a workspace-scoped key.

MethodPath
GET/v3/notifications/webhooks/categories
GET / POST/v3/notifications/webhooks
GET / PUT / DELETE/v3/notifications/webhooks/{webhook_id}
POST/v3/notifications/webhooks/{webhook_id}/enable
GET/v3/notifications/webhooks/{webhook_id}/notifications
GET/v3/notifications/webhooks/{webhook_id}/notifications/{notification_id}
POST/v3/notifications/webhooks/{webhook_id}/notifications/{notification_id}/resend
POST/v3/notifications/webhooks/{webhook_id}/notifications/resend

PUT replaces the endpoint's name, description, URL and categories — send all of them; a description left out is cleared. Wire IDs use TypeID prefixes whk_ (endpoint) and whn_ (notification). Create accepts name, description, categories[], and url (absolute http/https); up to 5 endpoints per workspace, each on its own URL. The URL is stored normalized — scheme and host lower-case, the default port dropped — with its path kept as typed (a trailing slash makes a different URL). The host must be reachable on the public internet: localhost, internal names and private, loopback or link-local addresses are refused, and deliveries follow at most three redirects, never to a private address. Categories are accounts, compliance, banking, crypto, wallets and trade; an endpoint receives every event type in the categories it selects (GET /v3/notifications/webhooks/categories lists them).

Deliveries keep the payload, headers and signature described in the webhook guide. Each event reaches each endpoint under one webhookId (also sent as X-BlockWyre-Webhook-ID): it stays the same across retries and resends, and in the rare case an event is delivered to the same endpoint twice it arrives with the same id both times — deduplicate on it. A delivery is tried up to 6 times — the first attempt and 5 retries — until the endpoint answers 2xx or 3xx, retrying with exponential backoff: about 7 to 14 minutes from the first attempt to the sixth. Each attempt times out after 30 seconds. When one delivery fails all six attempts the endpoint is disabled, and POST …/enable turns it back on. The delivery log keeps 60 days. Inbound provider webhooks stay on /v3/webhooks/{provider}/… and are unrelated to this surface.

A resend delivers a logged delivery again: the same payload, under the same notification id and webhookId, as a new attempt on it. POST …/notifications/{notification_id}/resend resends one and answers 204. POST …/notifications/resend resends, in one action, every failed delivery of the endpoint written in a range, newest first, spread out (about ten a second) so an endpoint just back from an outage is not flooded. Its body is created_at_gte (required) and created_at_lte (optional; absent is now), both RFC 3339 and inclusive, for example {"created_at_gte": "2026-10-01T00:00:00Z", "created_at_lte": "2026-10-02T00:00:00Z"}. It resends up to 500 per request and answers 200 with {"resent": 12, "has_more": false}: when has_more is true, send the same request again for the next batch. Both refuse a disabled endpoint: re-enable it first.

Errors come in three kinds:

  • 422 — a required field is missing. A create or PUT without name, url or categories, or a delivery-log search q shorter than 3 characters, answers 422 with the message Validation failed and one entry per field in details (for example {"field": "body.url", "message": "url is a required field"}).
  • 400 — the request does not parse. A malformed id in the path (whk_…, whn_…), or a category or status the API does not know, answers 400 with the message failed to parse request.
  • 400 — the form parses but breaks a rule, with a resource-specific code: webhook_invalid_name, webhook_invalid_description, webhook_invalid_url (not an absolute http/https URL), webhook_url_not_public (a well-formed URL whose host is not reachable on the public internet — localhost, an internal name, a private, loopback or link-local address), webhook_no_categories (an endpoint must listen to at least one category), notification_invalid_category (an empty category in the list) and webhook_invalid_resend_range (a bulk resend without created_at_gte, or with created_at_lte before it).

401 unauthorized: no dashboard session, or an API key or customer session. 403 forbidden: the member's role lacks the permission. 404 codes: webhook_not_found and notification_message_not_found. 409 codes: webhook_limit_exceeded, webhook_duplicate_url, webhook_disabled (a resend, single or bulk, on a disabled endpoint) and notification_message_in_flight (resend while the delivery is still in progress).