Skip to main content
Webhooks are part of Salty, the CRM built for AI agents — see trysalty.com for the product overview and pricing. When data changes in a Salty workspace, registered webhook endpoints receive a signed POST with the new state. A background worker fires pending deliveries within seconds and retries failures with an exponential backoff. After 8 consecutive failures the endpoint is marked inactive and a webhook_endpoint.failed meta-event fans out to any other still-active endpoints in the same workspace.

Register an endpoint

Response (the signing_secret is shown once; store it):
Subsequent reads of the endpoint (GET /webhook-endpoints or GET /webhook-endpoints/:id) omit signing_secret.

Signature

Every delivery carries:
Verify by computing HMAC-SHA-256 over <timestamp>.<body> with your whsec_… secret, then compare with constant-time equality. Reject deliveries older than 5 minutes to prevent replay.

Verifier (Node)

Payload shape

delivery_id is unique per delivery — use it for idempotent receiver-side processing (the same event may be re-delivered after a transient receiver failure).

Retry schedule

1s → 5s → 30s → 5min → 30min → 2h → 12h between attempts. After the 8th attempt fails, the delivery is marked failed, the endpoint flips is_active = false, and a webhook_endpoint.failed meta-event fans out to other still-active endpoints in the workspace:
To re-enable a deactivated endpoint, delete it and create a new one. (v1.1 will add a re-enable endpoint.)

Events

Subscribe to "*" for everything, or pass a list of exact event names (no glob patterns in v1).

API surface

Test endpoint

Synchronously POSTs {event: "webhook_endpoint.test", data: {ping: "pong"}} to your URL and returns the receiver’s HTTP status + body. Doesn’t enqueue, doesn’t retry — just a single fire to confirm wiring is right.

Delivery audit

status is one of: pending, in_flight, delivered, failed. next_retry_at is the next scheduled attempt for pending rows; null once terminal.