Error envelope

API-level errors use a consistent shape:
  • code — stable machine-readable identifier; branch on this, not message.
  • message — human-readable explanation, safe to log.
Two exceptions use their own formats:
  • 422 validation errors follow the framework shape: { "message": "...", "errors": { "amount": ["..."] } }
  • 429 rate limits return { "message": "Too Many Attempts." }

Status codes

Retry guidance

  • Reads (GET): safe to retry any number of times.
  • POST /payments/stk: retry only on 503 / network timeout after checking that no transaction already exists for the same account_reference (list transactions) — otherwise the customer could get a second payment prompt.
  • Webhook deliveries: we retry for you (up to 5 attempts). Your endpoint should also be idempotent: process the same uuid + event more than once without side effects.
Never log or return your API key or webhook secret. Error messages never contain secrets, but your own logs might if you echo request headers.