Receiving an HTTP request is the easy part of a webhook integration. The harder questions sit around it: what happened, who sent it, whether it has arrived before, and what the sender will do if the receiver cannot finish its work.
These questions form a contract. Writing that contract down is often more valuable than choosing a handler framework.
Identify the event, not just the object
A payload containing an invoice does not necessarily say whether the invoice was created, updated or paid. The event name may come from a header, a configured endpoint or another part of the provider’s protocol.
The go-invoice-ninja webhook implementation is a useful concrete example. Its documentation explains that Invoice Ninja’s payload represents the changed entity, while event identity and a shared secret are supplied through configured request details. Custom sender formats have separate handling. Assuming every provider sends the same envelope would miss this distinction.
Write down a representative request from the actual provider documentation. Include the method, event identity, authentication mechanism and expected response. Keep the example free of real credentials and customer data.
Decide what acceptance means
A successful response should have a defined meaning. Does it mean the request was validated and durably queued, or that all business processing completed? Either approach creates different failure and retry behavior.
If work continues after the response, the application needs a durable handoff and a way to observe failed processing. An in-memory promise that disappears when a process restarts is not the same as accepting responsibility for an event.
Where the provider can redeliver requests, use a stable delivery identifier or another documented deduplication strategy. Also check whether events can arrive out of order. A later-arriving request should not silently move a record backwards without a domain rule permitting it.
Make recovery ordinary
Keep enough operational information to answer three questions: was the request received, was it accepted, and was its effect applied? A correlation identifier and a clear processing status can help without filling logs with full payloads.
Test a duplicate, an unexpected event type, an oversized request and a temporary processing failure. Test authentication failure separately from malformed input. These cases teach more about the integration than a single successful sample.
Finally, document how to replay or reconcile a missed event. Delivery systems fail in ways that cannot all be hidden behind retries. A dependable webhook integration has a recovery story that a person can understand and carry out when the automatic path stops working.