Integrations

Webhooks

Send purchases, renewals, signups and other events to your own endpoint: add a webhook, test it, verify the signature, read delivery health, redeliver, and pause or delete.

6 min readLast updated Sep 30, 2026

A webhook sends a message to an address of yours every time a chosen event happens in your workspace, for example a new purchase. When you finish, you will have an active webhook, a signing secret to verify its messages, and a place to watch deliveries. Webhooks are part of every current Zanfia plan.

Add a webhook

1

Open Webhooks

In the sidebar open Workflows → Webhooks (/workflows/webhooks) and click Add webhook. A full-page form titled Add webhook opens (/workflows/webhooks/new).

2

Enter the address

Paste the address of your endpoint into Webhook URL. It has to be a full URL, for example https://domain.com/hook; anything else is rejected before the form can be saved or tested.

3

Add headers or basic auth (optional)

Open Custom headers and basic auth. Add header adds a key and a value that are sent with every delivery. Basic auth credentials takes a Username and a Password. "Credentials are stored encrypted and never shown again": when you edit the webhook later, header values show as unchanged and you only type them to replace them.

4

Choose the events

Under Which events should we send? tick at least one event. The events are grouped into Sales & checkout, Subscriptions & access, Customers and Milestones & referrals; the full list is in the table below.

5

Send a test

In Test your webhook URL pick an event and click Send test. The dark box shows the exact message that is sent. A green notice "Test delivery sent - endpoint responded 200" means your endpoint answered; an answer outside the 200 range shows as a warning, and "Test delivery failed - the endpoint could not be reached" means the address did not respond at all. Test messages carry "test": true.

6

Save and copy the signing secret

Leave Active on and click Save webhook. A window titled Your webhook signing secret shows a code starting with whsec_. Copy it and click OK. You are back on the list; the new row shows a POST tag, the address, its events, and the Active switch turned on.

Good to know

The signing secret is not lost if you skip copying it. Open the webhook, click Edit, and use Reveal next to Signing secret. Roll secret generates a new one: "The current secret stops validating immediately. Deliveries keep flowing, but your server must be updated with the new secret to verify them."

Events you can subscribe to

GroupEvent in the formevent value in the message
Sales & checkoutNew purchaseproduct.ProductPurchased
Free signup completedproduct.FreeSignupCompleted
Form submittedform.FormSubmitted
Order created (incl. failed payment)product.OrderCreated
Order refundedproduct.OrderRefunded
Checkout abandonedcheckout.CheckoutAbandoned
Subscriptions & accessEnd of subscriptionproduct.ProductSubscriptionEnd
Subscription renewalproduct.ProductSubscriptionRenewed
Renewal of the access periodproduct.ProductAccessRenewed
End of access periodproduct.ProductAccessPeriodEnd
14 days, 7 days, 3 days, 1 day until the end of the access periodproduct.ProductAccessPeriodEndingIn14Days, …In7Days, …In3Days, …In1Day
CustomersSubscribed to the newsletterclient.SubscribedToAudience
Tag added to a customerclient.TagAdded
Subscriber went quietclient.Unengaged
The client has been importedproduct.ClientImported
Client archived in the productproduct.ProductClientArchived
Client removed from the productproduct.ProductClientRemoved
Milestones & referralsCourse completedcourse.CourseCompleted
Validated referralproductReferrals.ValidSubscriberFromReferral
Referral reward earnedproductReferrals.ReferralRewardEarned

The 14-day notice is sent only for access lasting at least 3 months.

What a delivery looks like

Every delivery is an HTTP POST with a JSON body and these headers, plus any custom headers and basic auth you configured:

HeaderValue
X-Zanfia-EventThe event name, so you can route without parsing the body
X-Zanfia-Signaturet=[unix time],v1=[signature], see below
X-Zanfia-Testtrue, present only on test messages sent from the dashboard

The body always has the same envelope. The keys listed under data are always present and are null when the event carries no value for them; an event can add its own extra keys (for a purchase: productName, paymentType, quantity, price).

{
  "apiVersion": "2026-07-13",
  "event": "product.ProductPurchased",
  "occurredAt": "2026-09-30T10:00:00.000Z",
  "workspaceId": "your workspace id",
  "data": {
    "clientId": "cli_4f81c92a7b3d",
    "clientEmail": "anna.novak@example.com",
    "clientFirstName": "Anna",
    "clientLastName": "Novak",
    "clientName": "Anna Novak",
    "productId": "prod_8c31a2f4d95e",
    "priceId": "price_5e92c7d1a48b",
    "orderId": "35e479ee-d456-4ee9-a5da-e7ff8109ffcc",
    "checkoutId": "chk_1f83b6a92c4d",
    "orderTotalAmount": 199,
    "consents": [{ "name": "marketing", "value": true }],
    "utmSource": "facebook",
    "utmMedium": "cpc",
    "utmCampaign": "summer-launch",
    "utmTerm": null,
    "utmContent": null
  }
}

The preview box in the editor shows the body for whichever event you select, so use it as the reference for each event's extra keys.

Verify the signature

Each delivery carries X-Zanfia-Signature: t=[unix time],v1=[signature]. The signature is the HMAC-SHA256, in hex, of the text [t].[raw body] (the t value, a dot, then the request body exactly as received), computed with your signing secret. On your server:

  1. Read t and v1 from the header.
  2. Compute HMAC-SHA256 over t, a dot and the raw request body, with the whsec_ secret as the key.
  3. Compare your result with v1 using a constant-time comparison, and reject the request if they differ.

Compute over the raw body, before any JSON parsing; a re-serialized body produces a different signature.

Monitor, redeliver, pause and delete

The list at /workflows/webhooks has four columns: Endpoint, Events, Health and Active.

What you seeMeaning
Healthy, with the time of the last deliveryRecent deliveries succeeded.
"[n]/[m] recent deliveries failed"Some recent deliveries failed.
No deliveries yetNothing was sent so far. Test messages from the editor are not counted.
Auto-paused next to the switch"Paused automatically after 15 failed deliveries in a row. Fix the endpoint, then switch it back on."

Click a row to open Webhook details: the address, its state, its events, and Recent deliveries with time, status and response. The redeliver arrow on a delivery sends that event again through the webhook's current settings ("Delivery re-sent - endpoint responded 200"). The buttons at the bottom are Delete ("Delete this webhook?"), Send test and Edit.

To pause a webhook without deleting it, turn its Active switch off in the list; it stops receiving events until you turn it back on.

Webhooks inside workflows

If a workflow of yours contains a webhook action, its address appears in a second table, Used in workflows, with the workflows that call it and the same health and delivery history. Those endpoints are edited in the workflow itself, not here. See Build a workflow for workflows.

Was this article helpful?

Related articles

Spotted something off? Tell us at support@zanfia.com.