> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.zip.tax/v-6-0/guides/webhooks/best-practices/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.zip.tax/_mcp/server. # Best practices A few habits make webhook integrations robust. Follow these when building your handler. ## Acknowledge fast, then do the work Return a `2xx` status **immediately** to acknowledge receipt, then do any heavy work (fetching rates, updating your database) asynchronously. Slow handlers risk timing out before they acknowledge. ## Treat the payload as a trigger After a `rate.updated` event, call the [Ziptax rate API](../rest-api/overview) to fetch the authoritative updated rates for the indicated authority. Do not treat the webhook body as the source of truth for rate values. It only tells you **which** authority changed. ## Make handlers idempotent Be prepared to receive the same event more than once. Design your handler so that processing a duplicate event is harmless (for example, key your work off the authority in the payload rather than blindly appending records). ## Verify authenticity Use your [signing secret](verify) to confirm requests are genuinely from Ziptax once the verification scheme is published. Until then, keep your endpoint URL private and rely on re-fetching authoritative data from the API. ## Use HTTPS Serve every production endpoint over `https://`. This protects the payload in transit and is required for a secure integration. ## A minimal receiver The same handler is shown below in Node.js, Python, and Go. Use the tabs to switch languages. Each one acknowledges quickly with a `2xx`, then treats the event as a trigger to re-fetch rates for the indicated authority. These are illustrative starting points; adapt them to your stack. #### Node.js ```javascript import express from "express"; const app = express(); app.use(express.json()); app.post("/webhooks/ziptax", (req, res) => { // TODO: verify the X-Signature header using your Ziptax signing secret (whsec_...) // See "Verify & secure deliveries" for a full example. const { event, data } = req.body; if (event === "rate.updated") { const { locality, code } = data.rateUpdateDetail; // A rate changed for this authority. Fetch the latest rates from the Ziptax API. console.log(`Rate updated for ${locality} ${code}`); } // Acknowledge quickly. res.sendStatus(200); }); app.listen(3000); ``` #### Python ```python from flask import Flask, request app = Flask(__name__) @app.post("/webhooks/ziptax") def ziptax_webhook(): # TODO: verify the X-Signature header using your Ziptax signing secret (whsec_...) # See "Verify & secure deliveries" for a full example. payload = request.get_json() if payload.get("event") == "rate.updated": detail = payload["data"]["rateUpdateDetail"] # A rate changed for this authority. Fetch the latest rates from the Ziptax API. print(f"Rate updated for {detail['locality']} {detail['code']}") # Acknowledge quickly. return "", 200 ``` #### Go ```go package main import ( "encoding/json" "log" "net/http" ) type webhookEvent struct { Event string `json:"event"` Data struct { RateUpdateDetail struct { Locality string `json:"locality"` Code string `json:"code"` } `json:"rateUpdateDetail"` } `json:"data"` } func main() { http.HandleFunc("/webhooks/ziptax", func(w http.ResponseWriter, r *http.Request) { // TODO: verify the X-Signature header using your Ziptax signing secret (whsec_...) // See "Verify & secure deliveries" for a full example. var evt webhookEvent if err := json.NewDecoder(r.Body).Decode(&evt); err != nil { w.WriteHeader(http.StatusBadRequest) return } if evt.Event == "rate.updated" { d := evt.Data.RateUpdateDetail // A rate changed for this authority. Fetch the latest rates from the Ziptax API. log.Printf("Rate updated for %s %s", d.Locality, d.Code) } // Acknowledge quickly. w.WriteHeader(http.StatusOK) }) log.Fatal(http.ListenAndServe(":3000", nil)) } ``` > **Info** > > This minimal receiver leaves signature verification as a `TODO` to stay short. > In production, verify the `X-Signature` header before trusting a delivery. See > [Verify & secure deliveries](verify) for a full example. > Patterns for reliable, secure webhook handling