We wrote this document for webhook providers to copy and adapt to their own webhook delivery configuration. Most segments can be fully copied, a few others require you to select the option for your docs. Watch out for the tooltips and callouts.

What are webhooks?

Webhooks are a mechanism for notifying third-party applications about a change in their account in real time. Oftentimes, APIs are able to respond immediately to API calls, but not all the time, in scenarios like this, a webhook event is used to notify the third-party app via a Webhook URL.

Event Types

Find a way to document all your supported event types and their accompanying payload. Use the one below, only as a guide.
    "event_type": "invoice.created",
    "data": {
        "id": "inv_3234aei32489aie2o3245",
        "status": "created"

Retry Behaviour

Convoy supports two types of retry strategies: linear, and exponential backoff, based on your configuration you can use any of the below to communicate with your users.

Swap out the specific delay and duration according to your config.
In production, if your endpoint does not respond with a 2xx, 
we continue to retry the event every n seconds for a 
maximum of n hours.

Webhook Verification

There are two ways you can verify webhooks from . Let’s take a look at both methods and what safe guards they provide.

Static IPs

With this verification method, you can configure your firewalls to receive webhooks from only the following IP addresses, while blocking out the rest.

If you’re a cloud customer, select the IP addresses from the region your cluster is deployed

Signature Verification

With this verification method, we’re able to determine if the webhook came from , and has not been tampered with in transit. We use Convoy, and they provide SDKs for the following languages:

Make sure to substitue the encoding, hash, and header for your configuration. Supported values for them are:

  • encoding: hex, base64.
  • hash: SHA256, SHA512.
  • header: provider specific. E.g. X-Paystack-Signature.
import (
    convoy "github.com/frain-dev/convoy-go/v2"

func HandleWebhook(w http.ResponseWriter, r *http.Request) {
    body, err := io.ReadAll(r.Body)
    if err != nil {

    webhook := convoy.NewWebhook(
            Hash: "SHA512",
            Secret: os.Getenv("WEBHOOKS_ENDPOINT_SECRET"),
            Payload: body,
            Encoding: "hex",
            SigHeader: "X-Convoy-Signature",
    err = webhook.VerifyRequest(r)
    if err != nil {

    // write webhook to queue.

Consuming webhooks best practices.

You can freely copy and paste this segment.
  1. Always return early. If you have a long running process that you’d like to executed preferably push that to a background job to process, and return quickly with a 2xx.
  2. Favour Idempotent processing. All webhooks are delivered with a X-Convoy-Idempotency-Key header which can be used for Idempotent processing.
  3. Default to HTTPS endpoints. Webhooks are endpoint exposed to the internet, for safety, we default to HTTPS only URLs, and validate the certs.