Verify a proposed receiver
Configured receiver URLSent by the provider to the receiver configured on the instance.
Sent to the exact configured URL before creating an instance or replacing its delivery configuration. Signed with the proposed secret. The receiver must verify the signature and expected registration before echoing the challenge. Only a 200 response with the matching challenge within 10 seconds succeeds. A bare 2xx response is insufficient. Redirects are not followed. One attempt per provisioning or update attempt; this is not retried on the notification schedule. Failures leave no active new configuration. Registration retries must be rate limited and coalesced. The instance ID may be reserved before creation, but is not yet usable. registration_id echoes delivery.registration_id from the proposed configuration. The receiver uses it to select a preconfigured secret, then verifies the original body bytes before trusting the instance ID or answering the challenge. Unknown registrations must be rejected.
Webhook Signature
Standard Webhooks v1 HMAC-SHA256 authentication. Remove whsec_ from the
configured signing_secret and base64-decode it to obtain the key bytes.
Sign the UTF-8 bytes of webhook-id, a period, webhook-timestamp, a period,
and the exact transmitted body bytes. Send v1, followed by the base64
digest. No instance credential or provisioner token is sent to receivers.
Verify using a constant-time comparison and the locally configured key.
Reject attempt timestamps more than five minutes from the receiver's
clock. The header can contain space-separated signatures; a valid v1
signature is required. Never trust a secret supplied in the message.
Parameters
| Field | Type | Description |
|---|---|---|
webhook-idrequired | header · Identifier | The message ID, equal to body.id. Stable across notification retries. |
webhook-timestamprequired | header · string | Delivery attempt time as Unix seconds, as required by Standard Webhooks. |
Request body
application/json · required
A provisioner-generated UUID identifying an expected configuration on the receiver before the provider assigns an instance ID. Install its association with the signing secret on the receiver before provisioning or updating. Reuse it on retries of the same submission; generate a new value for a replacement configuration. It is a lookup hint, not a secret or proof of authenticity. The provider echoes it in verification messages.
An RFC 3339 timestamp in UTC, ending in Z.
A fresh unpredictable UUID challenge bound to this configuration attempt.
View complete schema and constraints
{
"type": "object",
"additionalProperties": false,
"required": [
"id",
"type",
"registration_id",
"instance_id",
"created_at",
"challenge"
],
"properties": {
"id": {
"$ref": "#/components/schemas/Identifier"
},
"type": {
"type": "string",
"const": "webhook.verification"
},
"registration_id": {
"$ref": "#/components/schemas/WebhookRegistrationID"
},
"instance_id": {
"$ref": "#/components/schemas/Identifier"
},
"created_at": {
"$ref": "#/components/schemas/Timestamp"
},
"challenge": {
"$ref": "#/components/schemas/Identifier",
"description": "A fresh unpredictable UUID challenge bound to this configuration attempt."
}
}
}{
"id": "c9bb5281-f9a5-4660-b27e-0b1cbbad81b6",
"type": "webhook.verification",
"registration_id": "8246931c-4ce0-4c15-a94a-e9c078ad06e2",
"instance_id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
"created_at": "2026-09-16T11:59:00Z",
"challenge": "2edc34d7-cc57-44b1-8705-2fa608d3224a"
}Responses
| Status | Meaning | Body |
|---|---|---|
200 | The receiver accepts this registration and echoes its challenge. | WebhookVerificationResponse |
400 | The verification message is malformed. | No body |
401 | The signature or delivery timestamp is invalid. | No body |
403 | The receiver does not accept this registration. | No body |
429 | The receiver is rate limited; verification fails for this attempt. | No body |
200 response
The exact challenge from the verified, expected registration message.
View complete schema and constraints
{
"type": "object",
"additionalProperties": false,
"required": [
"challenge"
],
"properties": {
"challenge": {
"$ref": "#/components/schemas/Identifier",
"description": "The exact challenge from the verified, expected registration message."
}
}
}{
"challenge": "2edc34d7-cc57-44b1-8705-2fa608d3224a"
}Notify a receiver of a terminal request
Configured receiver URLSent by the provider to the receiver configured on the instance.
Sent to the instance's current verified URL. This is a notification only; retrieve the decision through the authenticated approval API. The message ID and body stay fixed across retries and receiver updates. Each attempt has a fresh delivery timestamp and signature. webhook-id equals body.id.
Any 2xx acknowledges durable receipt, not execution. The receiver must verify the signature, save or queue the notification, and deduplicate before arranging resumption. Duplicates already saved receive 2xx too. The provider retries failures with exponential backoff and jitter until acknowledgement or seven days (168 hours) after decision.decided_at. There must be at most one outstanding attempt per event. Each attempt has a timeout of at most 10 seconds and must end by that deadline. Respect Retry-After on 429 and 503 within the retry window. Do not follow redirects. Removal of delivery or deletion of the instance ends retries. Approval expiry does not end notification delivery.
Retain the request, creation idempotency key and notification until the later of seven days after the decision or 24 hours after delivery ends. If delivery is removed whilst an attempt is in flight, the grace period starts after that attempt finishes. Receivers retain duplicate tracking through the retry window and grace period; eight days after event creation covers both. Retention does not preserve access for revoked credentials. Replacing the receiver does not restart the delivery window.
Webhook Signature
Standard Webhooks v1 HMAC-SHA256 authentication. Remove whsec_ from the
configured signing_secret and base64-decode it to obtain the key bytes.
Sign the UTF-8 bytes of webhook-id, a period, webhook-timestamp, a period,
and the exact transmitted body bytes. Send v1, followed by the base64
digest. No instance credential or provisioner token is sent to receivers.
Verify using a constant-time comparison and the locally configured key.
Reject attempt timestamps more than five minutes from the receiver's
clock. The header can contain space-separated signatures; a valid v1
signature is required. Never trust a secret supplied in the message.
Parameters
| Field | Type | Description |
|---|---|---|
webhook-idrequired | header · Identifier | The message ID, equal to body.id. Stable across notification retries. |
webhook-timestamprequired | header · string | Delivery attempt time as Unix seconds, as required by Standard Webhooks. |
Request body
application/json · required
A transport-independent notification of a terminal request, generated for approved, denied, expired and cancelled outcomes. created_at equals decision.decided_at. The provider creates one immutable event per request that becomes terminal whilst delivery is configured, except during instance deletion. It contains no decision, tool arguments or credentials. Fetch the authoritative request through the authenticated API.
An RFC 3339 timestamp in UTC, ending in Z.
View complete schema and constraints
{
"type": "object",
"additionalProperties": false,
"required": [
"id",
"type",
"instance_id",
"request_id",
"created_at"
],
"description": "A transport-independent notification of a terminal request, generated\nfor approved, denied, expired and cancelled outcomes. created_at equals\ndecision.decided_at. The provider creates one immutable event per request\nthat becomes terminal whilst delivery is configured, except during\ninstance deletion. It contains no decision, tool arguments or credentials.\nFetch the authoritative request through the authenticated API.\n",
"properties": {
"id": {
"$ref": "#/components/schemas/Identifier"
},
"type": {
"type": "string",
"const": "request.resolved"
},
"instance_id": {
"$ref": "#/components/schemas/Identifier"
},
"request_id": {
"$ref": "#/components/schemas/Identifier"
},
"created_at": {
"$ref": "#/components/schemas/Timestamp"
}
}
}{
"id": "f4b96ac4-404d-4f6a-9a03-a0565edc4922",
"type": "request.resolved",
"instance_id": "b29a43a7-1949-4b9f-9d61-b7ae66f85d31",
"request_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
"created_at": "2026-09-16T12:02:00Z"
}Responses
| Status | Meaning | Body |
|---|---|---|
400 | The notification is malformed. | No body |
401 | The signature or delivery timestamp is invalid. | No body |
429 | Reduce delivery rate to this destination and respect Retry-After. | No body |
503 | The receiver is temporarily unavailable. Respect Retry-After. | No body |
2XX | Signature verified and receipt durably recorded. Any response body is ignored. | No body |
Error and retry response headers
429
| Header | Type | Description |
|---|---|---|
Retry-After | header · string | The delay before retrying, in seconds or as an HTTP date. |
503
| Header | Type | Description |
|---|---|---|
Retry-After | header · string | The delay before retrying, in seconds or as an HTTP date. |