The official PHP client for the Fortpesa API. Whole-KES integers everywhere (like the API), typed exceptions per error class, an idempotency key on every STK Push, and built-in webhook signature verification.

GitHub

Source code, examples and issue tracker.

Packagist

fortpesa/fortpesa-php - releases and version history.

Requirements

  • PHP 7.4+ (tested on 8.3)
  • ext-curl and ext-json - no other dependencies

Install

Create the client

API keys are created in your dashboard under Settings → API keys. Never embed keys in client-side code. Optional settings:

STK Push

channel_id is required on every request, and your service wallet needs enough balance to cover the platform fee. Channel IDs are listed on the Payment channels page of your dashboard.

Transaction status

Service wallet balance

Retries and idempotency

payments->stk() always sends an Idempotency-Key: yours if given, otherwise a random one. The client retries network errors, 429, 500, 502 and 504 (up to max_retries, default 2, exponential backoff, Retry-After honoured) only for GETs and idempotent POSTs. 503 CIRCUIT_OPEN is not auto-retried; wait about a minute. If the same key is replayed, the API returns the original transaction and $tx->replayed is true - a flaky network can never double-prompt a customer.

Error handling

Typed exceptions per error class, with the API error.code available for branching:
All of them extend FortpesaException; the HTTP ones extend ApiException (getHttpStatus(), getErrorCode(), getErrors(), getResponseBody()). Codes are in Fortpesa\ErrorCode. See the errors reference for the full code list.
Bad local input (amount < 1, reference > 12 chars, malformed phone…) throws \InvalidArgumentException before anything is sent.

Verify webhooks

HMAC-SHA256 over the raw body, constant-time compare, 5 minute replay window:
If you can’t read php://input directly (frameworks, WordPress REST), pass the raw body yourself:
Never verify against re-encoded JSON - it changes the bytes and breaks the signature.
See Webhooks for the event catalogue and retry schedule.

Next steps