Webhooks
Webhooks let Workstation tell your systems when something changes. You register an endpoint URL and pick the events you care about. When a matching change happens, Workstation sends a signed POST request with the event to that URL and retries it if your server does not answer.
For example, you can notify your ERP when a deal is won, or update a data warehouse whenever a contact changes.
Open Settings → Integrations & Developers → Webhooks. You need the Settings → Manage permission to add or change endpoints; Settings → View can see them.
Add an endpoint
Section titled “Add an endpoint”- Click Add endpoint.
- Enter the Endpoint URL, such as
https://example.com/webhooks/repzo. - Optionally add a Description of what the endpoint is for.
- Under Events to send, pick events or turn on Send all events. “All events” also includes event types added in the future.
- Optionally add Custom headers, such as
X-Api-Key, if your server expects them. - Save. Copy the Signing secret from the endpoint page.
A workspace can have up to 20 endpoints. Each endpoint can have up to 20 custom headers. Custom headers cannot replace the signing or transport headers that Workstation sets.
Events
Section titled “Events”Each object that can be customized in Objects sends .created, .updated, and .deleted events, for example deal.created. Some objects also send more specific events:
| Object | Extra events |
|---|---|
| Contact | contact.stage_changed, contact.owner_changed, contact.loyalty_points_changed, contact.loyalty_tier_changed |
| Account | account.stage_changed, account.owner_changed |
| Deal | deal.stage_changed, deal.won, deal.lost, deal.owner_changed |
| Ticket | ticket.status_changed, ticket.assigned |
| Order | order.stage_changed |
| Listing | listing.stage_changed |
| Subscription | subscription.status_changed, subscription.paused, subscription.resumed |
| Price offer | price_offer.sent, price_offer.status_changed |
| Invoice | invoice.finalized, invoice.voided, invoice.payment_recorded, invoice.paid, invoice.payment_removed |
| Form | form.published, form.archived |
| Activity | activity.completed |
| Campaign | campaign.status_changed |
Products only send the three standard events. The event picker shows a short description of every event.
What a delivery looks like
Section titled “What a delivery looks like”Every request body is a JSON event:
{ "id": "evt_...", "object": "event", "type": "deal.updated", "apiVersion": "2026-10-01", "createdAt": "2026-10-13T09:30:00.000Z", "orgId": "...", "test": false, "actor": { "type": "user", "id": "..." }, "data": { "object": { "id": "...", "name": "Renewal 2027", "amount": "1200.00" }, "previousAttributes": { "amount": "1000.00" } }}data.objectuses the same shape as the record in the public REST API, so the same parsing code works for both.previousAttributesappears on updates and holds the old values of the fields that changed.- Payment events also include
data.payment; loyalty events includedata.loyalty.
Delivery order is not guaranteed. Use createdAt and the event id to sort and de-duplicate.
Verify the signature
Section titled “Verify the signature”Webhooks follow the Standard Webhooks scheme, so any Standard Webhooks or Svix library can verify them. Each request has three headers:
| Header | Value |
|---|---|
webhook-id |
The event id. It stays the same across retries, so use it to ignore duplicates. |
webhook-timestamp |
Unix time in seconds |
webhook-signature |
v1,<base64 HMAC-SHA256> |
To check a request yourself, compute an HMAC-SHA256 over {webhook-id}.{webhook-timestamp}.{raw body}, using the base64 part of your whsec_ secret as the key, and compare it to the signature. Reject requests with an old timestamp.
Rotate the secret
Section titled “Rotate the secret”On the endpoint page, click Rotate secret. Choose Keep old secret 24 hours to update your server without failed checks (both signatures are sent during that time), or Expire old secret now.
Retries and failures
Section titled “Retries and failures”Your server should answer with any 2xx status within 15 seconds. Otherwise Workstation retries the delivery after 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, and 10 hours (8 attempts in total).
If every delivery to an endpoint fails for 5 days, Workstation disables the endpoint and notifies admins. To recover:
- Fix the endpoint and turn Enabled back on.
- Under Retry failed events, choose a date and click Retry failed to send what the endpoint missed.
Deliveries also pause while the workspace is suspended for billing.
Test and debug
Section titled “Test and debug”- Send a test event on the endpoint page sends a sample event with
"test": true. Test events are not retried and never count toward disabling. - The endpoint’s Deliveries list filters by All, Succeeded, Failed, and Retrying. Open a delivery to see the request headers and body, every attempt, and your server’s response. Click Resend to send it again.
- The Event log tab lists every event, which record triggered it, and which endpoints received it.
Events, deliveries, and attempts are kept for 30 days.
Webhooks in sandboxes
Section titled “Webhooks in sandboxes”A sandbox can have its own webhook endpoints, so you can test an integration against test data before connecting it to your live workspace.