PalmPesa
Collect payments with PalmPesa
PalmPesa (Eagle Star Technology) is a Tanzanian mobile-money collection gateway. Centipid Billing pushes a payment request to the payer’s wallet, the payer authorizes it on their handset, and the subscriber is provisioned once PalmPesa confirms the order.
PalmPesa is offered to ISPs in Tanzania (TZ), alongside ClickPesa, AzamPay, PawaPay, PesaPal, Relworx, ZenoPay, PayPal, and DPO. Provider API documentation is published at documentation.palmpesa.co.tz.
Before you start
- Complete PalmPesa merchant onboarding in an account owned by the ISP, and have the account verified.
- Collect the API token from the PalmPesa dashboard.
- Confirm the settlement account and the currency PalmPesa will settle in.
- Confirm your Centipid Billing host is reachable from the public internet, so PalmPesa can deliver callbacks.
Configure the gateway
Open Settings → Payments → PalmPesa
Select PalmPesa from the payment marketplace to open its configuration form.
Enter the API token
API token (required) is issued on your PalmPesa dashboard once the account is verified. It is stored as a secret and is not echoed back into the form after saving.
Leave the API host blank unless PalmPesa told you otherwise
API host (optional) overrides the endpoint Centipid Billing calls. Leave it empty to use the default PalmPesa endpoint. Only set it if PalmPesa has issued your account a different host.
Save and switch
Saving validates the form; it does not prove the token works. Switching to PalmPesa requires the API token to be present and may require an OTP confirmation.
Run a controlled test payment
Pay a small amount from the captive portal. Verify the wallet prompt arrives, the payment lands in the ledger with method PalmPesa, and the subscriber’s package is applied. See the limitation below before testing from the customer portal.
Credentials
| Field | Required | Notes |
|---|---|---|
| API token | Yes | Secret. Issued on the PalmPesa dashboard after account verification. The only field required to switch to PalmPesa. |
| API host | No | Falls back to the platform default endpoint. Enter a full URL, for example https://palmpesa.co.tz. |
What the payer must provide
PalmPesa rejects a payment request that carries no email address. Centipid Billing supplies one for you — payers are never asked to type an address.
- Email address (supplied automatically). Neither the captive portal nor the customer portal asks the payer for an email. The subscriber’s saved profile email is used when there is one; otherwise an address is derived from the phone number being paid with, on an unroutable domain. A hotspot payer with no account can therefore pay normally. If PalmPesa ever emails a receipt, only payers with a real profile email will receive it.
- Tanzanian phone number (required). Accepted as
07…,06…, or with the255country code; the number is normalized before it is sent. - Amount. Rounded to a whole number before the request is sent.
Because authorization happens on the payer’s handset rather than in a hosted checkout page, no PalmPesa domain needs to be added to the captive walled garden for the payer’s browser.
How a payment completes
Request
Centipid Billing calls PalmPesa’s V2 async API,
POST /api/v2/async/payments. PalmPesa answers with anorder_id, which becomes the local transaction reference that everything afterwards reconciles against.Authorization
The payer approves the request on their phone.
Confirmation
A background job polls
GET /api/v2/async/payments/{order_id}every 5 seconds, for up to 40 attempts (about 3 minutes 20 seconds), until the order reaches a terminal state. This poller — not the callback — is what completes the payment, so a payment still completes when the payer closes the captive browser mid-checkout.The captive portal never asks PalmPesa itself. It shows whatever the poller last recorded, so a payer who declined the prompt sees the failure on the next status check instead of waiting out the 2-minute checkout timeout.
Provisioning
On
COMPLETED, a payment is recorded with method PalmPesa and the subscriber’s package is applied asynchronously. OnFAILED,CANCELLED,EXPIREDorREJECTED, PalmPesa’s failure reason is stored against the transaction and nothing is credited.
A failed request is deliberately not retried automatically. PalmPesa documents no idempotency on the request reference, so an automatic retry after a lost response could raise a second order and prompt the payer twice. The payer retries by choice instead.
Troubleshooting
| Symptom | What it means | What to do |
|---|---|---|
| “PalmPesa API token not configured” | No API token is saved. | Enter the API token in Settings → Payments → PalmPesa. |
| “PalmPesa authentication failed. Check the API token” | PalmPesa rejected the token (HTTP 401). | Re-copy the token from the PalmPesa dashboard. Confirm the account is verified and the token has not been rotated. |
| “A valid Tanzanian phone number is required for PalmPesa payments” | The number could not be normalized to a Tanzanian MSISDN. | Re-enter the number as 07…, 06…, or 2557…. |
| “Could not reach PalmPesa. Please try again” | The request could not reach the PalmPesa endpoint. | Check outbound connectivity from the application host, and any custom API host value. |
| Customer portal shows “Unable to start the payment” but the payer still got a wallet prompt | The known customer-portal limitation above. The push succeeded; only the portal’s response is wrong. | Check the ledger before advising anything. Do not tell the payer to retry. Use the captive portal for PalmPesa payments. |
| Payer paid, but the transaction sits pending | The order never reached a terminal state within the polling window. | Confirm the payment on the PalmPesa dashboard, then raise it with support with the order id and the payer’s phone number. |
For symptoms that are not specific to PalmPesa, see Payment troubleshooting. For every other gateway’s fields, see the credential reference.
