Skip to main content

Webhooks: Get notified when something changes in Ignition

Have Ignition notify your systems when clients, proposals or invoices change. Webhooks are part of the Core API and need a developer to set up.

Written by Pat Kuo

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

client.created

A client is added

client.updated

A client's details change

client.archived

A client is archived

Contacts

contact.created

A contact is added

contact.updated

A contact's details change

contact.deleted

A contact is removed

Proposals

proposal.created

A proposal is created

proposal.sent

A proposal is sent to the client

proposal.accepted

The client accepts a proposal

proposal.completed

A proposal is completed

proposal.lost

A proposal is marked as lost, or expires

proposal.updated

A proposal is reverted to draft or renewed

proposal.archived

A proposal is archived

Invoices

invoice.created

An invoice is issued

invoice.paid

An invoice is paid in full, however the payment is recorded

invoice.updated

An invoice is partially paid, marked unpaid, or its due date changes

invoice.voided

An invoice is voided

invoice.archived

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

  1. Create a Core API app if you don't already have one. See Core API.
    ​

  2. Call the Core API to register your webhook, with your HTTPS URL and the list of events you want.
    ​

  3. Copy the signing secret from the response and store it somewhere safe. It starts with whsec_ and is only shown once.
    ​

  4. 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... }
}

  • data holds 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.

  • source shows what caused the change. channel is app for changes made in Ignition, and application_slug identifies 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:

  1. Take the raw request body exactly as received.
    ​

  2. Join the timestamp and the body with a period, as t.body.
    ​

  3. Compute the HMAC-SHA256 of that string with your signing secret.
    ​

  4. Compare the result to v1 using 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_at to 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.

Did this answer your question?