NamibraPay

Webhooks

Webhooks are how NamibraPay tells your server that money moved — the moment a collection settles, a payout lands or a subscription renews. Configure one URL per environment; we sign every delivery.

Configure a webhook endpoint

Register an HTTPS URL per environment from the dashboard, or with the API. Sandbox events only ever go to your test URL and live events only to your live URL.

POST/api/v1/merchant/webhooks/config

Authenticates with your API keys.

Body parameters

ParameterDescription
urlrequiredstringHTTPS endpoint that will receive POST requests.
environmentrequiredstringtest or live — which environment delivers to this URL.
curl -X POST "https://api.namibrapay.com/api/v1/merchant/webhooks/config" \
  -H "X-API-Key: pk_test_xxxxxxxxxxxxxxxx" \
  -H "X-API-Secret: sk_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://api.yourapp.com/webhooks/namibrapay", "environment": "test" }'

Each configured environment gets a signing secret used to compute delivery signatures. You can rotate it at any time with POST /merchant/webhooks/config/{environment}/regenerate-secret.

Events

EventFired when
collection.initiatedA direct charge or checkout payment has been created and is awaiting the payer.
collection.processingThe provider accepted the charge; awaiting final confirmation.
collection.successThe collection settled — money is in your balance. Fulfil the order.
collection.failedThe payer declined or the charge failed.
payout.initiatedA payout was created and is pending.
payout.processingThe rail accepted the payout; funds are in flight.
payout.completedThe payout landed in the recipient account.
payout.failedThe payout was rejected; funds returned to your balance.
refund.initiatedA refund request was submitted.
refund.completedThe refund reached the customer.
dispute.createdA customer opened a dispute on a transaction.
dispute.resolvedThe dispute was resolved by support.
kyc.submittedYour compliance application was submitted.
kyc.approvedYour compliance application was approved — live keys unlock.
kyc.rejectedYour compliance application was rejected.
subscription.chargedA scheduled subscription debit succeeded.
subscription.payment_failedA scheduled subscription debit failed.

Payload

Every delivery is a POST with a JSON body and two headers: Content-Type: application/json and X-Webhook-Signature.

{
  "event": "collection.success",
  "timestamp": "2026-10-26T09:14:41.512Z",
  "data": {
    "reference": "NPR-k21jf9ds",
    "merchantReference": "ORDER-67890",
    "amount": 1000,
    "currency": "GHS",
    "channel": "mtn_momo",
    "status": "success"
  }
}

Verifying signatures

The X-Webhook-Signature header is an HMAC-SHA256 hex digest of the raw request body, keyed with your environment's signing secret. Verify it before processing anything.

Use the raw body

Compute the HMAC over the exact bytes we sent. If your framework parses the JSON first and you re-serialize it, key ordering and whitespace will differ and verification will fail — read the raw body (e.g. Express express.raw(), Flask request.get_data()).
# Test your endpoint's verification with a replay from the logs API:
curl -X POST "https://api.namibrapay.com/api/v1/merchant/webhooks/test" \
  -H "X-API-Key: pk_test_xxxxxxxxxxxxxxxx" \
  -H "X-API-Secret: sk_test_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "event": "collection.success" }'

Retries & timeouts

  • We wait up to 10 seconds for a response. Anything slower (or any non-2xx status) counts as a failure.
  • Failed deliveries are retried up to 5 times with exponential backoff starting at 5 seconds.
  • Respond 200 as fast as possible — do heavy work asynchronously, not inside the handler.

Best practices

  • Verify every signature before trusting a payload.
  • Make handlers idempotent — retries mean you may receive the same event more than once. Key your side effects on data.reference.
  • Don't rely on event order. A late reconciliation can deliver collection.success after you gave up on a timeout — handle state transitions, not just messages.
  • Confirm with the API for high-value flows. When a webhook triggers money movement, call the verify endpoint as a second check.

Logs & manual retries

Every delivery — successful or not — is recorded with its status code, response snippet and retry count. Inspect logs from the dashboard or the API, and replay any delivery:

GET/api/v1/merchant/webhooks/logs

Authenticates with your API keys.

POST/api/v1/merchant/webhooks/logs/{id}/retry
Re-deliver a logged event to your endpoint. The signature is recomputed at delivery time.

Authenticates with your API keys.

POST/api/v1/merchant/webhooks/test
Send a synthetic test event to your configured endpoint — handy during setup.

Authenticates with your API keys.

GET /api/v1/merchant/webhooks/logs

200
{
  "success": true,
  "data": [
    {
      "id": "wl_9fj21kda",
      "event": "collection.success",
      "url": "https://api.yourapp.com/webhooks/namibrapay",
      "httpStatus": 200,
      "success": true,
      "retryCount": 0,
      "createdAt": "2026-10-26T09:14:42.100Z"
    }
  ]
}