Webhooks Overview
Build reliable integrations that react to changes in Probo
Webhooks let your application react when resources change in Probo without polling the API. A subscription connects one HTTPS endpoint to a set of events in one organization. When an event occurs, Probo sends a signed POST request containing a JSON snapshot of the affected resource.
Common uses include synchronizing users and third parties, starting document approval workflows, and recording compliance events in another system.
How it works
Section titled “How it works”-
Expose an HTTPS endpoint
Your endpoint must accept
POSTrequests with anapplication/jsonbody. -
Create a subscription
In Probo, open Settings > Webhooks, enter the endpoint URL, and select the events to receive. You can also manage subscriptions with the CLI.
-
Verify every delivery
Verify the signature against the raw request body and reject stale timestamps before parsing or acting on the payload.
-
Acknowledge quickly
Persist or enqueue the event, then return an accepted
2xxresponse. Perform slow work asynchronously.
Endpoint requirements
Section titled “Endpoint requirements”- The URL must use HTTPS.
- The endpoint must return
200,201,202, or204. - The complete response must arrive within 30 seconds.
Any other status, connection error, or timeout marks the delivery as failed. Probo does not retry failed deliveries, so monitor delivery history and design a recovery process for missed events.
Root envelope
Section titled “Root envelope”Every delivery body is a JSON object with a fixed root envelope. Resource-specific fields live under data (and optionally updatedFrom) — they are never promoted to the root.
{ "eventId": "whevt_01ABC123", "subscriptionId": "whsub_01DEF456", "organizationId": "org_01GHI789", "eventType": "document:updated", "createdAt": "2026-07-15T10:30:00Z", "data": { "id": "doc_01VWX234", "title": "Information Security Policy" }, "updatedFrom": { "id": "doc_01VWX234", "title": "InfoSec Policy" }}| Root field | Type | Always present | Description |
|---|---|---|---|
eventId |
string | Yes | Unique delivery ID. Use it as an idempotency key |
subscriptionId |
string | Yes | Webhook subscription that received the event |
organizationId |
string | Yes | Organization where the event occurred |
eventType |
string | Yes | Wire-format event name (e.g. document:updated, third-party:created) |
createdAt |
string | Yes | When the event was created (RFC 3339) |
data |
object | Yes | Current resource payload for the event. Shape depends on eventType — see Event Types |
updatedFrom |
object | No | Present only on *:updated events. Full snapshot of the same resource shape as data, taken before the update. Omitted for create, delete, archive, signature, and other non-update events |
Process a delivery safely
Section titled “Process a delivery safely”- Verify the signature using the headers and untouched request body.
- Parse the JSON only after verification succeeds.
- Confirm
organizationIdandeventTypeare ones your endpoint expects. - Atomically record
eventIdbefore producing side effects. Ignore an ID you have already processed. - Enqueue the event and return a successful response.
For update events, compare updatedFrom with data to identify the change. Resource IDs such as a document or user ID are nested under data; they are not root fields.
HTTP headers
Section titled “HTTP headers”Each request also carries metadata in headers. Some headers mirror root envelope fields so you can route or reject a delivery before parsing the body.
| Header | Mirrors body field | Description |
|---|---|---|
Content-Type |
— | Always application/json |
X-Probo-Webhook-Event |
eventType |
Wire-format event name (e.g. document:updated) |
X-Probo-Webhook-Organization-Id |
organizationId |
Organization ID |
X-Probo-Webhook-Timestamp |
— | Unix timestamp in seconds used when computing the signature |
X-Probo-Webhook-Signature |
— | Hex-encoded HMAC-SHA256 of {timestamp}:{rawBody} |
X-Probo-Webhook-Host |
— | Hostname of the Probo instance that sent the delivery (for multi-region / self-hosted receivers) |
Header vs body
Section titled “Header vs body”| Use case | Prefer |
|---|---|
| Signature verification | Headers (X-Probo-Webhook-Timestamp, X-Probo-Webhook-Signature) + raw body bytes |
| Fast allow/deny before JSON parse | Headers (X-Probo-Webhook-Event, X-Probo-Webhook-Organization-Id, X-Probo-Webhook-Host) |
| Business logic / diffs | Root envelope + data / updatedFrom |
| Idempotency | Root eventId |
subscriptionId and createdAt exist only in the body root — they are not duplicated as headers.
Signing secret
Section titled “Signing secret”Probo generates a signing secret prefixed with whsec_ for each subscription. Store it in a secret manager, scope it to the receiving service, and never log it or include it in client-side code. The secret is required to verify webhook signatures.
Delivery behavior
Section titled “Delivery behavior”- Probo polls for pending events approximately every 5 seconds and processes them sequentially.
- A delivery succeeds only when the endpoint returns
200,201,202, or204within 30 seconds. - Failed deliveries are not retried automatically.
- Probo stores the response status, headers, and up to 64 KB of the response body for troubleshooting.
- Delivery status is
PENDING,SUCCEEDED, orFAILED.
Review delivery history under Settings > Webhooks. Avoid returning secrets or sensitive records in your response body because the response is retained for debugging.
Receiver checklist
Section titled “Receiver checklist”- Preserve the raw body until signature verification is complete.
- Accept requests only from expected organizations and event types.
- Use
eventIdto make processing idempotent. - Queue work before sending the response.
- Alert on
FAILEDdeliveries and reconcile missed changes. - Ignore unknown JSON fields so additive payload changes do not break your receiver.