Skip to main content

Webhooks

Webhooks send an HTTPS POST to your server whenever something changes, so you don't have to poll.

Set up​

In the dashboard, go to Settings → Webhooks → New and fill in:

  • Endpoint: an https:// URL on your server.
  • Challenge: a secret string that you choose.
  • Events: the events to subscribe to.

Events​

topicFires whenPayload
collection_eventAn invoice is created or changes stateInvoice
send_money_eventA payout batch changes stateBatch status
reversal_eventA chargeback is created or changes statusChargeback
wallet_transfer_eventAn intra-wallet transfer or split completesfrom_data, to_data, amount
subscription_eventA subscription's status, cycles or failure reason changesSubscription with payments[]

Payload​

The body is the resource itself, plus topic and your challenge:

{
"invoice_id": "ABC123",
"state": "COMPLETE",
"provider": "M-PESA",
"value": 100,
"net_amount": 97,
"currency": "KES",
"account": "254712345678",
"api_ref": "order-123",
"provider_ref": "QWE123RTY",
"failed_reason": null,
"failed_code": null,
"topic": "collection_event",
"challenge": "my-secret-challenge"
}

Handling webhooks​

  1. Verify the challenge. Reject any request whose challenge doesn't match yours.
  2. Respond with 200 or 201 quickly. Any other status counts as a failure.
  3. Be idempotent. You may get more than one event per resource (one per state change). Key your handling on invoice_id / tracking_id and state.
  4. Confirm critical events. Before you release goods, call payment status.
# Flask
@app.post("/intasend/webhook")
def intasend_webhook():
event = request.get_json()
if event.get("challenge") != os.environ["INTASEND_WEBHOOK_CHALLENGE"]:
return "", 401
if event["topic"] == "collection_event" and event["state"] == "COMPLETE":
fulfil_order(event["api_ref"], event["invoice_id"])
return "", 200

Failures and replay​

Failed deliveries are recorded under Webhooks → Events in the dashboard, and you can replay them from there. If your endpoint fails repeatedly, IntaSend emails you a warning and then disables the endpoint. Re-enable it in the dashboard once it's fixed.