Skip to content

Webhook endpoints

Scopes: webhooks:write to set or stop, webhooks:read to look. Live only — the test-mode endpoint is set on the dashboard.

Where events go, managed by the server that receives them, so a deploy that moves your server to a new host can move the endpoint in the same pipeline rather than waiting for somebody to open a browser. One address per mode, and the mode is the key's: a live key manages the live endpoint.

POST /v1/webhook_endpoints

json
{ "url": "https://shop.example.co.tz/pamopay/events" }

Response 201

json
{
  "id": "17",
  "object": "webhook_endpoint",
  "mode": "live",
  "url": "https://shop.example.co.tz/pamopay/events",
  "active": true,
  "created": "2026-09-17T09:14:02.118Z",
  "updated": "2026-09-17T09:14:02.118Z",
  "secret": "whsec_7Fk2Ba91Az44Qd81p7c9Xb04t2n"
}

Setting a new address rotates the signing secret — the old server may not be yours any more — and returns the new one. Setting the same address keeps it. The secret is derived rather than stored, so unlike an API key it can be read again on the Developers screen.

Refusals: BAD_URL — not https, no host, credentials in the URL, or over 500 characters.

GET /v1/webhook_endpoints

The endpoint for the key's mode, active or not, never with the secret.

json
{ "object": "list", "has_more": false, "data": [ { "id": "17", "object": "webhook_endpoint", "…": "…" } ] }

DELETE /v1/webhook_endpoints/{id}

Stops sending. Events that happen afterwards are recorded as unrouted and stay readable at GET /v1/events, so nothing is lost while there is no address. Never actually deleted: the delivery history points at it. Another business's endpoint id is NOT_FOUND.

A deploy step

bash
curl -sS -X POST "$BASE/v1/webhook_endpoints" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d "{ \"url\": \"https://$NEW_HOST/pamopay/events\" }" \
  | jq -r .secret > /run/secrets/pamopay_whsec

The key doing this needs webhooks:write and nothing else; keep it separate from the key that takes payments.

Every code, scope and route on this site is rendered from the API's own source.