Receiver sequence
Verify bytes before trusting an event.
Acknowledgement follows signature, timestamp, schema, and deduplication checks—not merely receipt of HTTP.
- 01ReceiveKeep raw body
- 02VerifyTimestamp + v1 signatures
- 03ValidateHeaders + schema
- 04DeduplicateClaim event ID
- 05AcknowledgeAfter durable claim
- DeliverSigned event
- RetryNon-2xx
- DuplicateSame event ID
- DisableContract boundary
Machine-readable event contract: https://cleanedweb.com/asyncapi.json.
Signed webhooks deliver finalized saved-search events to a customer HTTPS endpoint. Configuration is currently managed by a signed-in workspace owner or administrator in the CleanedWeb portal. Webhook management endpoints are not part of the public property OpenAPI contract.
Event mapping
| Saved-search selection | Public event type |
|---|---|
new_match |
property.match.created |
price_changed |
property.price.changed |
status_changed |
property.status.changed |
Live events use schema_version: property-event-v1. Validate against:
https://cleanedweb.com/schemas/property-event-v1.jsonhttps://cleanedweb.com/examples/webhook-event.json
The stable event id is the deduplication key. Delivery is at least once and order
is not guaranteed across properties or retry attempts. Commit the event ID and
business change atomically before acknowledging the request.
A connection test uses type: webhook.test, contains 0 records and 0 Units, and is
not a property-event-v1 live event.
Signature verification
CleanedWeb uses the Standard Webhooks HMAC-SHA256 wire format. Preserve the exact raw request bytes; parsing and re-serializing JSON changes the signed content.
Read these headers:
webhook-idwebhook-timestampwebhook-signature
For each space-separated v1,BASE64_SIGNATURE value, compute HMAC-SHA256 over:
webhook-id + "." + webhook-timestamp + "." + raw_request_body
Decode the base64 material after the whsec_ prefix to obtain the signing key.
Compare signatures in constant time and accept the event when any current signature
matches. During secret rotation, old and new signatures can both be present for 24
hours. Reject timestamps outside the receiver's explicit clock-skew policy.
Return a 2xx response only after durable acceptance. Redirects and other status
codes are failures.
Retries and endpoint state
Transport failures and non-2xx responses retry on this schedule:
- 5 seconds
- 5 minutes
- 30 minutes
- 2 hours
- 5 hours
- 10 hours
- 14 hours
- 20 hours
- 24 hours
There are at most 10 attempts in a delivery cycle. A valid Retry-After is honored
between 1 second and 24 hours. HTTP 410 is terminal. Exhausted delivery or a
terminal endpoint moves the connection to needs_attention.
After fixing and testing the endpoint, a workspace administrator can replay failed webhook deliveries from the previous 7 days. Replays preserve the event ID, so the same deduplication rule applies.
Freshness and system-of-record boundary
Webhook delivery begins after an observer event is finalized. It is not evidence of source-real-time acquisition. Fetch the canonical property endpoint when current state matters; a failed notification does not imply a failed property update.
The event envelope can contain data.record_count and data.units. Do not treat
those values or an HTTP status as the billing ledger. Runtime unit_costs, workspace
receipts, and the Unit ledger are authoritative when available.
Receiver checklist
- Accept only HTTPS requests on the intended route.
- Limit request size before buffering the raw body.
- Verify timestamp and signature before processing data.
- Validate
property-event-v1and reject unknown versions. - Deduplicate by event
idin durable storage. - Commit before returning
2xx. - Monitor repeated failures and portal
needs_attentionstate.
Standards and further reading