Guide to Zift Webhooks: Features and Best Practices
Zift webhooks (Zift calls them notifications) notify your application about billing and processing activity: a subscription is created, a payment is processed, a chargeback or return occurs. If you're building on Zift, notifications are how you react to these events without polling.
This guide covers how Zift notifications work, the acknowledgement handshake, why there's no signature to verify, and the best practices for production.
What are Zift webhooks?
Zift notifications are HTTPS POSTs carrying a JSON body. There is no signing secret, no signature header, and no Basic or token auth on delivery. This is confirmed from the full rendered docs, not an absence of documentation. Authenticity relies only on HTTPS and endpoint-URL secrecy, so treat Zift's source as unverified passthrough and add your own controls. To acknowledge each delivery, your endpoint must return JSON {"notificationId": <id>}.
Zift webhook features
| Feature | Details |
|---|---|
| Delivery | HTTPS POST, JSON body |
| Verification | None documented (no secret, no signature header, no token auth) |
| Acknowledgement | Return JSON {"notificationId": <id>} (int or string) |
| Retries | On non-ack: +5min, +15min, +60min, +24h, then status "Failed" (no further redelivery) |
| Payload | notificationId, eventCode (e.g. billing.subscription-created), eventDate (epoch-ms), dataType, data{} |
| Setup | Out-of-band: email Zift support your HTTPS endpoint and events (integrator/reseller level) |
| SDK | None |
Common events
Zift has a naming quirk: the trigger names you subscribe to use tildes, while the eventCode in the payload uses dots. Map between them:
| Trigger name | Payload eventCode (example) |
|---|---|
subscription~create | billing.subscription-created |
payment-option~create | billing payment-option created |
allocation~create | billing allocation created |
payment~process | billing payment processed |
chargeback | processing chargeback |
return | processing return |
reversal | processing reversal |
NOC | processing NOC |
Subscribe with the tilde trigger names, but branch your handler on the dotted eventCode in the payload.
Setting up Zift webhooks
Setup is out-of-band: email Zift support your HTTPS endpoint and the events you want. Notifications are configured at the integrator or reseller level, not per merchant. There's no self-serve dashboard and no secret to store, so keep your endpoint URL secret and consider IP allowlisting.
Securing Zift webhooks
There's no signature to verify, so security rests on transport and process. Serve the endpoint over HTTPS only, keep the URL secret, and consider allowlisting Zift's source IPs. Acknowledge every delivery by echoing its notificationId, otherwise Zift retries and eventually marks the notification "Failed".
app.post("/webhook", express.json(), (req, res) => {
// No signature to verify. Authenticity rests on HTTPS + URL secrecy (+ optional IP allowlist).
const { notificationId, eventCode } = req.body;
// Acknowledge by echoing the notificationId, or Zift will retry and then mark it Failed
res.json({ notificationId });
// Branch on the dotted eventCode (payload), not the tilde trigger name (subscription)
processQueue.add({ eventCode, body: req.body }); // async, dedupe on notificationId
});
The same handler in Python (FastAPI):
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/webhook")
async def zift_webhook(request: Request):
body = await request.json()
# No signature to verify; acknowledge by echoing notificationId
enqueue(body) # async; branch on body["eventCode"], dedupe on notificationId
return {"notificationId": body["notificationId"]}
Zift webhook limitations and pain points
There's no signature to verify
The Problem: Zift delivers with no signing secret, signature header, or token auth. You can't cryptographically prove a request came from Zift, so a leaked URL is enough for anyone to post events.
Why It Happens: Zift's notification delivery relies on HTTPS and URL secrecy.
Workarounds:
- Serve HTTPS only, keep the endpoint URL secret, allowlist Zift's source IPs, and validate the payload shape before acting.
How Hookdeck Can Help: Hookdeck can front the endpoint, apply IP allowlisting and its own controls, and give you a managed layer in front of an unverifiable source.
Acknowledgement must echo the notificationId
The Problem: A plain 200 isn't enough. Zift treats a delivery as acknowledged only when you return {"notificationId": <id>}. Miss it and Zift retries, then marks the notification "Failed".
Why It Happens: Zift confirms delivery by matching the echoed id.
Workarounds:
- Return
{"notificationId": <id>}with the exact id from the request.
How Hookdeck Can Help: Hookdeck can manage the acknowledgement contract at the edge, so a missed echo doesn't fail deliveries.
Trigger names and eventCode differ
The Problem: You subscribe to tilde names like subscription~create, but the payload carries dotted codes like billing.subscription-created. Branching on the trigger name instead of the eventCode never matches.
Why It Happens: Zift uses different naming for subscription triggers and payload codes.
Workarounds:
- Subscribe with tilde names, but branch handlers on the dotted
eventCode.
How Hookdeck Can Help: Hookdeck's filters route on the eventCode you actually receive, so the naming mismatch doesn't leak into your app.
Retries end in a terminal Failed state
The Problem: On non-ack, Zift retries at +5m, +15m, +60m, +24h, then marks the notification "Failed" with no further redelivery. A prolonged outage means permanently lost events.
Why It Happens: Zift's retry schedule is finite.
Workarounds:
- Acknowledge fast and reliably, and reconcile via the API for anything that reached "Failed".
How Hookdeck Can Help: Hookdeck durably queues events and retries on its own schedule, so a downstream outage doesn't drop events at Zift's terminal state.
Best practices
Treat the source as unverified passthrough
There's no signature, so rely on HTTPS, URL secrecy, IP allowlisting, and payload-shape validation.
Echo the notificationId to acknowledge
Return {"notificationId": <id>} with the exact id, or the delivery isn't acknowledged.
Branch on the dotted eventCode
Subscribe with tilde trigger names, but handle events by the payload eventCode.
Return the ack fast and process asynchronously
Acknowledge quickly and defer work to a queue; dedupe on notificationId. See why to process webhooks asynchronously.
Make Zift webhooks production-ready
Hookdeck fronts your endpoint, manages the ack, deduplicates, and durably queues every notification
Conclusion
Zift notifications have no documented signature verification, so authenticity rests on HTTPS and URL secrecy, treat the source as unverified passthrough. Acknowledge each delivery by echoing {"notificationId": <id>}, or Zift retries at +5m/+15m/+60m/+24h then marks it "Failed". Subscribe with tilde trigger names, branch on the dotted eventCode, and dedupe on notificationId.
Hookdeck fronts your endpoint, manages the acknowledgement, deduplicates, and durably queues every notification at the edge, so your app processes a reliable, unique stream.
Get started with Hookdeck for free and handle Zift webhooks reliably in minutes.