Skip to main content

Troubleshooting Guide

A symptom-driven guide to resolving the most common AfriRoute integration problems. Each section lists likely causes and concrete fixes. When opening a support ticket, always include the request_id from the error response.

๐Ÿ”‘ Authentication Failures (401 / 403)โ€‹

Symptom: MISSING_API_KEY, INVALID_API_KEY, or FORBIDDEN_SCOPE.

  • Confirm the header is exactly Authorization: Bearer $AFRIROUTE_API_KEY โ€” not Authorization, not Bearer:.
  • Verify you are using the correct key for the environment ($AFRIROUTE_API_KEY for production, $AFRIROUTE_API_KEY for sandbox).
  • Check the key has not been revoked or rotated in the dashboard.
  • For FORBIDDEN_SCOPE, ensure the key's scopes include the product you're calling.
  • For IP_NOT_ALLOWED, add your server's egress IP to the key's allowlist.

โฑ๏ธ Rate Limiting (429)โ€‹

Symptom: RATE_LIMIT_EXCEEDED or QUOTA_EXCEEDED.

  • Read X-RateLimit-Remaining and X-RateLimit-Reset on each response to pace requests.
  • Honor the Retry-After header before retrying.
  • Implement exponential backoff (see snippet below).
  • If you consistently hit limits, upgrade your plan or request a custom limit.
async function withBackoff(fn, max = 5) {
for (let i = 0; i < max; i++) {
const res = await fn();
if (res.status !== 429) return res;
const wait = (parseInt(res.headers.get('Retry-After')) || 2 ** i) * 1000;
await new Promise((r) => setTimeout(r, wait));
}
throw new Error('rate limit: retries exhausted');
}

๐Ÿ“ต Message Not Deliveredโ€‹

Symptom: SMS shows failed / UNDELIVERABLE.

  • Validate the recipient is in E.164 format (+251911234567, not 0911234567).
  • Confirm the destination country is supported.
  • Use a registered sender ID โ€” unregistered IDs are filtered in many markets.
  • Check wallet balance; INSUFFICIENT_BALANCE silently blocks sends.
  • Some networks block promotional content during quiet hours โ€” schedule within business hours.

๐Ÿ’ฐ Payment Stuck or Failingโ€‹

Symptom: PAYMENT_DECLINED, INSUFFICIENT_FUNDS, or a transaction stuck in pending.

  • A pending mobile-money charge is normal until the payer approves the prompt; rely on the payment.completed webhook, not the synchronous response.
  • For DUPLICATE_TRANSACTION, reuse the original reference instead of generating a new one.
  • For PROVIDER_UNAVAILABLE, retry after a short delay โ€” the provider, not AfriRoute, is down.

๐Ÿ”” Webhooks Not Arrivingโ€‹

Symptom: No callbacks reach your server.

  • Confirm the endpoint is publicly reachable over HTTPS (test with curl from outside your network).
  • Verify the webhook is enabled and subscribed to the right events.
  • Check the Delivery Log in the dashboard for response codes and bodies.
  • Ensure you respond with 2xx within 10 seconds, or events are retried then dead-lettered.
  • Behind a proxy/load balancer? Make sure it forwards the raw body and X-AfriRoute-Signature header.

๐Ÿ” Signature Verification Failsโ€‹

Symptom: Your handler computes a different signature than X-AfriRoute-Signature.

  • Sign the raw request body, not a re-serialized JSON object โ€” re-serialization changes byte-for-byte content.
  • Include the timestamp: HMAC input is "{t}.{raw_body}".
  • Use the correct whsec_... secret for that specific webhook.
  • Use constant-time comparison. See Webhook Security.

๐Ÿชช Identity Verification Rejectedโ€‹

Symptom: IMAGE_QUALITY_LOW, FACE_MISMATCH, or LIVENESS_FAILED.

  • IMAGE_QUALITY_LOW: re-capture with even lighting, no glare, the document filling the frame.
  • FACE_MISMATCH: ensure the selfie is frontal and recent; lower min_confidence only if your risk policy allows.
  • LIVENESS_FAILED: confirm a live capture (not a photo of a screen) and that the active challenge matches.
  • REGISTRY_UNAVAILABLE: retry later; government registries have intermittent downtime.

๐Ÿงช General Debugging Checklistโ€‹

  1. Reproduce against the sandbox base URL first.
  2. Capture the full error envelope including request_id.
  3. Compare your request to the documented schema field by field.
  4. Confirm clock sync on your server (NTP) โ€” skewed clocks break signature timestamps and JWTs.
  5. Escalate to [email protected] with the request_id and a minimal repro.

Last Updated: May 2026 | Need help? [email protected]