Skip to main content

Customers & wallets

Beyond one-off payments, the API lets you manage customers under your company and hold a running wallet balance for each of them — useful for stored value, loyalty balances, or any flow where a customer tops up once and spends later (including paying for a checkout invoice straight from their wallet).

All endpoints on this page require your company Bearer token (see Authentication) and are scoped to your company — you can only see and manage your own customers and their wallets.

:::tip Creating a customer creates their wallet There's no separate "create wallet" call. POST /v1/customers creates the customer and their wallet in one step. Every customer has a KES wallet with balance 0 from the moment they exist. :::

Create a customer​

curl -X POST https://sandbox.merchants.taifapay.africa/v1/customers \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+254712345678",
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Doe",
"metadata": { "crmId": "abc-123" }
}'

Only phoneNumber is required — it's the customer's primary identifier. Everything else (email, firstName, middleName, lastName, idNumber, metadata) is optional.

{
"message": "Customer created successfully",
"user": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"phoneNumber": "+254712345678",
"email": "jane@example.com",
"firstName": "Jane",
"lastName": "Doe",
"status": "active",
"createdAt": "2026-07-20T09:00:00.000Z",
"wallets": [
{ "id": "a1b2c3d4e5f6a7b8", "balance": 0, "currency": "KES" }
]
}
}

Store the returned id — it's what you use to look up the customer or their wallet later.

Look up a customer​

# By your platform's customer id
curl https://sandbox.merchants.taifapay.africa/v1/customers/{id} \
-H "Authorization: Bearer $ACCESS_TOKEN"

# By phone number (the primary identifier)
curl https://sandbox.merchants.taifapay.africa/v1/customers/phone/254712345678 \
-H "Authorization: Bearer $ACCESS_TOKEN"

Both return the customer with its current wallets[] balances. 404 if the customer isn't yours.

List customers​

curl "https://sandbox.merchants.taifapay.africa/v1/customers?page=1&limit=10&orderBy=createdAt_desc" \
-H "Authorization: Bearer $ACCESS_TOKEN"

Paginated (page, limit); optionally filter with where (a JSON string, e.g. {"status":"active"}) and sort with orderBy (field_asc / field_desc).

Update or deactivate a customer​

PATCH /v1/customers/{id} # update any subset of fields (name, KYC details, status, metadata, ...)
PATCH /v1/customers/{id}/deactivate # deactivate

Deactivating a customer sweeps any remaining wallet balance to your collections account (the cash is already sitting in your float from the original top-up) and reports how much in sweptAmount.

Wallet balances (company view)​

# Every wallet under your company, paginated
curl "https://sandbox.merchants.taifapay.africa/v1/wallets?page=1&limit=10" \
-H "Authorization: Bearer $ACCESS_TOKEN"

# One customer's wallet balance
curl https://sandbox.merchants.taifapay.africa/v1/wallets/{customerId} \
-H "Authorization: Bearer $ACCESS_TOKEN"

# One customer's wallet ledger (paginated with limit/offset)
curl "https://sandbox.merchants.taifapay.africa/v1/wallets/{customerId}/entries?limit=20&offset=0" \
-H "Authorization: Bearer $ACCESS_TOKEN"
{
"id": "a1b2c3d4e5f6a7b8",
"balance": 1500.5,
"currency": "KES"
}

Credit or debit a wallet​

You can adjust a customer's wallet balance directly from your backend — credit to top it up, or debit to deduct a payment:

curl -X POST https://sandbox.merchants.taifapay.africa/v1/wallets/{customerId}/adjust \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"direction": "credit",
"amount": 500,
"description": "Loyalty bonus",
"reference": "ADJ-2024-001"
}'
FieldRequiredNotes
directionyescredit (top up) or debit (deduct).
amountyes1 – 10,000,000, up to 2 decimal places.
descriptionnoReason recorded on the ledger entries (max 140 chars).
referencenoYour external reference for reconciliation (max 64 chars).

The response includes the wallet balance after the adjustment:

{
"transactionId": "wallet-adjustment-credit-2b8f...",
"walletId": "a1b2c3d4e5f6a7b8",
"direction": "credit",
"amount": 500,
"balance": 2000.5,
"currency": "KES",
"message": "Wallet credited successfully"
}

:::caution Debits can't overdraw A debit fails with 422 if the wallet balance is insufficient — no entry is posted. Check the balance first if you need to handle this gracefully. :::

This call is authorised solely by your company token and scoped to your own customers; the customer does not need to be present.

Customer-present top-up and pay-by-wallet (hosted checkout)​

Separately from the merchant-initiated adjustment above, a customer can top up or spend their own wallet while present, authenticating by SMS OTP on Taifa Pay's hosted checkout page:

  • Paying an invoice from wallet balance happens when the customer picks the "wallet" method on the hosted checkout page for a payment link you created. The page handles the OTP and the debit itself.
  • Topping up likewise happens inside that hosted experience, once the customer has authenticated there.

:::note Customer authentication isn't part of this API There's no endpoint here for registering or logging a customer in — for these customer-present flows you never mint or hold a customer's token. Your integration surface is the invoice and the resulting webhook. :::

Where to go next​

  • Hosted checkout — a customer can pay an invoice straight from their wallet via the hosted page
  • Direct payments & payouts — the M-Pesa/Pesalink endpoints wallet top-ups and settlements ride on
  • Webhooks — get notified when a wallet payment completes