Skip to main content
Fleet charging is paid from the fleet wallet. The wallet holds prepaid energy in kWh (balance_kwh), and fleets with a credit line can also charge on credit, which is billed later as usage invoices. Top-ups are paid through ExpressPay. The API cannot move money by itself: it creates a checkout, and a person completes the payment on the checkout_url page. Your system then hears about the result through webhooks. You need a key with wallet:write (create fundings, pay invoices) and fleet:read (quotes, wallet, fundings, invoices).
In the sandbox, nothing goes to ExpressPay. POST /wallet/fundings and POST /invoices/usage/pay with a sandbox key return a pending funding with checkout_url: null and sandbox: true. Settle it yourself with POST /sandbox/fundings/{fundingId}/succeed (the wallet is credited and wallet.funded fires) or /fail (wallet.funding_failed fires). Sandbox top-ups are never invoiced, so invoice_number stays null.

1. Check the wallet

Response
reserved_kwh is held by sessions in progress. debt is credit used and not yet repaid. max_charging_kwh is roughly how much energy the wallet can cover right now, prepaid and credit together. To be told when the balance runs low instead of polling, set a threshold with PATCH /fleet ({"low_balance_threshold_kwh": "500"}) and subscribe to wallet.low_balance.

2. Quote the top-up

Response
kwh is how much energy the amount buys at the fleet’s current unit_price. A quote is informational: the price is fixed when you create the funding.

3. Create the funding

amount is a JSON number in GHS with at most 2 decimal places. Idempotency-Key is required, and it also fixes the funding’s id, so use a new key for each top-up (see Idempotency).
Response (201)
The person who pays is identified to ExpressPay with the name, email and phone number of the fleet manager who created the API key. That account needs a phone number, or the request fails with 400 bad_request. If ExpressPay can’t start a checkout you get 503 service_unavailable and nothing is charged.

4. Send a person to checkout_url

Show or send the checkout_url to whoever pays for your fleet: open it in their browser, put it in an approval email, or link it from your finance tool. They complete the payment on ExpressPay’s page. Treat the URL as opaque. checkout_url is only present while the funding is pending. If someone loses the link, GET /wallet/fundings/{fundingId} returns it again.

5. Wait for wallet.funded

When ExpressPay confirms the payment, the wallet is credited and ChargeExpress sends wallet.funded with the funding:
data.object
If the payment fails you get wallet.funding_failed with status: "failed". Treat failed and expired as final. Outstanding credit is repaid first. If the fleet owes money when a top-up is paid, that part of the amount repays the debt (debt_repaid, oldest usage invoices first) and only the rest is credited as kWh (credited_kwh). Each usage invoice that becomes fully repaid sends invoice.paid.
No webhook endpoint yet? Poll GET /wallet/fundings/{fundingId}. While a funding is pending, that call also asks ExpressPay for the latest status, so it picks up payments even if a callback was missed.
Once ChargeExpress has issued the invoice for the purchase, you get invoice.created with a purchase invoice. Its id is the funding id, and invoice_number is also set on the funding. Download it with GET /invoices/purchase/{fundingId}/pdf.

Pay usage invoices

When sessions run on credit, each one gets a usage invoice whose id is the session id. List the unpaid ones:
Response
Then pay up to 50 of them in one checkout:
The response is a funding with a checkout_url, exactly as in step 3. The amount defaults to the invoices’ total amount_due; pass amount to pay part of it. When the payment completes, the selected invoices are repaid first, wallet.funded fires, and each invoice that is now fully paid sends invoice.paid. Download any invoice as a PDF with GET /invoices/{kind}/{invoiceId}/pdf, where kind is usage or purchase.