Webhooks: push Joinways events to your own tools
Have Joinways call your endpoint the moment a request, an event or a quote changes, with a signed payload you can verify.
Updated
A webhook is Joinways calling you instead of you asking Joinways. The moment something changes in your workspace, an HTTPS request lands on an address you own, carrying the record that changed. It is how you feed a data warehouse, a Slack channel of your own making, an accounting tool, or anything else that should react without someone re-typing it.
There are two separate mechanisms with the same name, and knowing which one you need saves an afternoon. This article covers both.
Which plan you need
Both routes are Pro features. The Developers section and the API that manages subscriptions require Pro, as do workflows.
The two kinds of webhook
- Subscriptions: you register an address once, and Joinways calls it every time a matching record changes anywhere in the workspace. This is what Zapier uses, and what you want for a general integration.
- The workflow action: one step inside a workflow, fired only for the events that rule matched, after its delay and its conditions. This is what you want when the call should carry your own business rule.
Subscriptions answer where is my data going; the workflow action answers when exactly should this fire. They can coexist on the same endpoint, and the header tells you which is calling.
Subscriptions
What you can subscribe to
Four event types, and this is the whole list:
- lead.created, when a new request lands in the Inbox.
- event.created, when an event is created.
- event.status_changed, when an event moves between Option, Confirmed, Lost or Cancelled.
- quote.status_changed, when a quote moves, signature included.
One subscription can listen to several of them. Event payloads arrive in the same shape as the API returns on GET /api/v1/events, so the same parsing code works on both.
Creating one
Two ways, and neither is a form in the app.
- Through Zapier: build a Zap on a Joinways trigger and the subscription is created for you.
- By calling POST /api/v1/webhooks yourself, with your target address and the event types you want.
The address must be public HTTPS. Loopback, private ranges and internal names are refused, so a local test needs a tunnel with a real public address.
Creation returns a signing secret, once and only once. Store it right away: Joinways never shows it again, and without it you cannot verify a single call.
Seeing and removing them
Settings then Developers lists every subscription on the workspace, with its address, the events it listens to, whether it is active or disabled, and when it was created. Deleting one there stops the deliveries immediately and cannot be undone.
Verifying a call
Every delivery carries an X-Joinways-Signature header, of the form sha256 followed by a hexadecimal digest. That digest is an HMAC-SHA256 of the raw request body, keyed with your secret.
To check it, compute the same HMAC over the body exactly as received, before any JSON parsing or reformatting, and compare the two. A body your framework has re-serialised will not match, and that is the most common cause of a verification that fails on a perfectly valid call.
Reject anything that does not match, and treat the secret as a credential: anyone holding it can forge a call that looks like ours.
Delivery, retries and auto-disabling
- Each delivery is attempted up to three times, with a short pause between attempts.
- A call that has not answered within ten seconds is treated as failed. Answer quickly with a 2xx and do your work afterwards.
- After ten consecutive failures a subscription is disabled automatically, rather than hammering a dead address forever.
- A webhook that fails never blocks the action inside Joinways. A booking still confirms even if your endpoint is down.
💡 Answer 200 as soon as you have the payload, then process it in the background. Endpoints that do their work before replying are the ones that end up auto-disabled.
The workflow action
Inside a workflow, Call a webhook sends the matched event to the address you give, after the rule's delay and conditions. The call carries a header naming it as coming from a workflow action, so an endpoint that also receives subscriptions can tell the two apart.
The signing secret is optional here: leave it empty for an unsigned delivery, or set one and get the same signature header as a subscription. The same public HTTPS rule applies.
Failures behave differently from subscriptions: a network error or a server error on your side is retried, a refusal such as a wrong address is recorded as skipped and not retried, because a misconfigured endpoint will not fix itself.
Which one to pick
- Mirroring your data somewhere, or driving Zapier, Make or n8n: a subscription.
- Calling something two days after an event ends, only for weddings over 100 guests: the workflow action, where the delay and the conditions live.
- Reading data on demand rather than being pushed it: neither. Use an API key and call the API.
Best practices
- Verify the signature on every call, without exception. An unverified endpoint is a public write channel into your systems.
- Make your handler idempotent: a retry can deliver the same change twice, and it should not create two rows.
- Subscribe only to what you use. Fewer event types mean fewer calls and a clearer log.
- Check the Developers list after a deployment on your side: a subscription silently disabled is the classic reason data stops arriving.
Troubleshooting
Nothing arrives at all
Cause: the subscription was auto-disabled after repeated failures, or it does not listen to the event type you are testing. Solution: open Settings then Developers, check its status and its events, and recreate it if needed.
The signature never matches
Cause: you are hashing a re-serialised body rather than the raw one. Solution: capture the body as received, before parsing, and hash that.
The address is refused at creation
Cause: it is not public HTTPS, or it points at a private or internal host. Solution: expose a real public address, with a tunnel for local development.
I lost the secret
Cause: it is shown once, at creation. Solution: delete the subscription and create a new one, which gives you a fresh secret.
Real-world example
A group wants every confirmed booking in its own reporting database within the minute. It subscribes an endpoint to event.status_changed, verifies the signature, and writes the row keyed on the event id so a retry updates rather than duplicates. Nobody exports anything by hand any more, and a quiet endpoint for ten calls in a row shows up as disabled in Developers rather than as silently missing data.
FAQ
Can I create a webhook from the app?
Subscriptions are created through Zapier or the API; the Developers page lists and deletes them. A workflow's webhook action is configured entirely in the workflow builder.
Which events exist?
Four: a request created, an event created, an event status changed, a quote status changed.
Is a delivery guaranteed?
It is attempted three times. After that the change is not replayed, so treat the API as your source of truth for a reconciliation.
Can several endpoints listen to the same event?
Yes. Every active subscription matching the event type receives it.
Does a failing webhook break anything in Joinways?
No. Delivery runs outside the action, so nothing in the app waits on your endpoint.
See also
- API keys
- Triggers, conditions and actions: the reference
- Plans and pricing
Ready to centralize your event inquiries?