Have Ignition tell your other systems the moment something happens, like a proposal being accepted, an invoice being paid or a client being added. Webhooks replace polling, so your integration hears about changes within seconds instead of asking the API every few minutes.
Available on every plan, in Early access. Webhooks are part of the Core API. Any Admin can turn on the Core API from Labs, and there's nothing to request. See Core API for setup.
Webhooks need a developer. They're created and managed through the Core API, and there's no webhooks screen in Ignition. If you'd rather connect Ignition to other apps without writing code, see Ignition and Zapier.
What webhooks do
A webhook is a URL you own. You give Ignition that URL and the events you care about, and Ignition sends it a short message each time one of those events happens in your practice.
Each message includes the record that changed, so your system can act on it straight away. For example, it could start onboarding when a proposal is accepted, or update your books when an invoice is paid.
Before you begin
You need:
The Core API turned on, and a Core API app. An Admin turns on the Core API in Labs, then creates the app in Settings → Developer hub. Core API walks through both.
A Core API app specifically. Webhooks belong to the app that creates them. A Reporting API app or an API key won't work, and Ignition rejects those requests.
Somewhere to receive them. An HTTPS URL that's reachable from the public internet and responds quickly.
Events you can subscribe to
Choose any combination of these 18 events for each webhook:
Event | Sent when |
Clients |
|
| A client is added |
| A client's details change |
| A client is archived |
Contacts |
|
| A contact is added |
| A contact's details change |
| A contact is removed |
Proposals |
|
| A proposal is created |
| A proposal is sent to the client |
| The client accepts a proposal |
| A proposal is completed |
| A proposal is marked as lost, or expires |
| A proposal is reverted to draft or renewed |
| A proposal is archived |
Invoices |
|
| An invoice is issued |
| An invoice is paid in full, however the payment is recorded |
| An invoice is partially paid, marked unpaid, or its due date changes |
| An invoice is voided |
| An invoice is archived |
Events fire whether the change was made in Ignition or through the API. For example, invoice.paid is sent however the payment is recorded.
How to set up a webhook
Create a Core API app if you don't already have one. See Core API.
Call the Core API to register your webhook, with your HTTPS URL and the list of events you want.
Copy the signing secret from the response and store it somewhere safe. It starts with
whsec_and is only shown once.
Check the signature on every delivery, as described below.
Please note: The signing secret can't be retrieved later, and repeating the request with the same idempotency key won't return it again. If you lose it, delete the webhook and create a new one.
For full request and response details, see the Core API developer documentation.
What a delivery looks like
Each delivery is a POST request with a JSON body like this:
{
"object": "event",
"type": "proposal.accepted",
"occurred_at": "2026-10-08T04:21:07Z",
"source": {
"channel": "app",
"application_slug": null
},
"data": { ...the proposal, in the same shape as the REST API... }
}
dataholds the record exactly as the REST API returns it, as it stands at the moment of sending. You can reuse the code you already have for reading API responses.sourceshows what caused the change.channelisappfor changes made in Ignition, andapplication_slugidentifies the app when a change came through the API. Use it to skip events caused by your own integration, so you don't create a loop.
Verify the signature
Every delivery includes an X-Ignition-Signature header, for example t=1760000000,v1=4f1c…. t is a Unix timestamp, and v1 is an HMAC-SHA256 signature made with your webhook's signing secret.
To verify a delivery:
Take the raw request body exactly as received.
Join the timestamp and the body with a period, as
t.body.
Compute the HMAC-SHA256 of that string with your signing secret.
Compare the result to
v1using a constant-time comparison.
Tip: Also reject deliveries with an old timestamp. A tolerance of five minutes stops anyone from replaying an intercepted delivery later.
When a delivery fails
Any response other than a success, including a timeout or connection error, counts as a failed delivery.
Ignition tries each delivery up to six times over roughly 24 hours. After the first attempt fails, it waits about 30 seconds, then 15 minutes, 1 hour, 6 hours and 16 hours between attempts. If your endpoint recovers within that window, the delivery still arrives.
Please note: A webhook that fails continuously for three days is turned off automatically. Deliveries stop until you fix the endpoint and turn the webhook back on, which also clears its failure history.
To avoid timeouts, respond to the delivery first, then do any slow processing afterwards.
Pause, resume or delete a webhook
Pause a webhook to stop deliveries without losing its settings, and resume it the same way.
Delete a webhook to remove it permanently.
Deleting the Core API app turns off every webhook that belongs to it.
Paused and turned-off webhooks don't queue events. Anything that happens while a webhook is off isn't delivered later.
Important information
You can have up to 10 webhooks per app.
URLs must be HTTPS and public. Local, private and internal addresses are rejected, so you'll need a tunneling tool to test against a computer on your own network.
Delivery history is kept for 30 days.
Past events can't be re-sent. If you miss some, read the current state from the API instead.
Order isn't guaranteed. Use
occurred_atto work out the sequence.The same event can arrive more than once. Make sure your integration handles a repeat safely.
Related articles
Still have questions? Reach out to our support team via the chat bubble or at help@ignitionapp.com and we'll be happy to help.
