Skip to content

POS charges

Scope: charges:write. Live only.

POST /v1/pos/charges

For a till system. You have rung up an amount at a counter (a six-digit till number printed on the sticker); you want a code the customer scans. No phone number is asked for — nothing is sent to anybody until the customer scans.

The code lives five minutes, deliberately short: a code left on screen after the customer leaves is one the next person in the queue could pay.

Headers: Idempotency-Key required. Use your sale number.

Body

Field
tillrequiredThe six digits on the counter, e.g. "400291".
amount_minorrequiredWhole shillings, TZS 100 – 20,000,000.
reference, description, metadata, currencyoptionalAs on a charge.

Response 201

json
{
  "id": "ch_01HZX…",
  "object": "charge",
  "state": "requires_payment",
  "till": "400291",
  "token": "7Kf2…",
  "qr": "https://pay.pamopay.co/c/1/7Kf2…",
  "amount_minor": 4650000,
  "mdr_minor": 0,
  "net_minor": 4650000,
  "currency": "TZS",
  "reference": "SALE-3391",
  "description": "",
  "metadata": {},
  "expires_at": "2026-09-16T09:19:02.118Z",
  "created": "2026-09-16T09:14:02.118Z"
}

Render qr as the QR code, verbatim. Do not build the URL yourself from token — the scheme, the /c/, and the version segment are ours to keep right, and a hand-built one will be refused by every handset. A customer with the PamoPay app installed opens the app directly; one without it opens a page saying which shop and how much.

Then poll GET /v1/charges/{id} or wait for charge.succeeded. The payment is made from the customer's PamoPay wallet, so the event's rail is wallet and it carries till so nine lanes can be told apart.

Refusals: BAD_TILL, UNKNOWN_TILL (not a till on this business), TILL_CLOSED, MERCHANT_NOT_LIVE, plus the charge ones.

The fee field is spelled differently here

The POS response spells the fee mdr_minor where /v1/charges spells it fee_minor. Read both if you share code between the two.

Opening further tills is done from the dashboard's Checkout screen, not the API.

Every code, scope and route on this site is rendered from the API's own source.