Payment links
Scopes: links:write to create, links:read to read. Live only.
POST /v1/payment_links
A price with a URL on it. No money moves when you create one; every payment against it is an ordinary charge created later, by the payer, on the hosted page.
Headers: Idempotency-Key optional. A link takes no money, so a duplicate is a second link you can see and close — but if your client sends one, a retry returns the link it made rather than a second URL, and the same key with a different price is IDEMPOTENT_MISMATCH.
Body
| Field | ||
|---|---|---|
amount_minor | required | Fixed price, whole shillings. |
title | required | 2–80 chars. What the payer is paying for. |
kind | optional | reusable (default) or single_use. |
max_uses | optional | Reusable only. Integer ≥ 1. |
expires_at | optional | ISO-8601, in the future. |
description | optional | ≤ 500 chars. |
reference | optional | ≤ 200 chars. |
success_url | optional | Where to send the payer afterwards. Must be https and on the website registered for your business at KYB. |
collect | optional | What the page asks whoever pays: any of "name", "phone", "email". See Knowing who paid. |
Response 201
json
{
"id": "pl_01HZX…",
"object": "payment_link",
"kind": "reusable",
"url": "https://pay.pamopay.co/l/9mQx…",
"amount_minor": 2500000,
"currency": "TZS",
"title": "Term 3 trip deposit",
"description": "",
"reference": "TRIP-T3",
"max_uses": null,
"used": 0,
"active": true,
"expires_at": null,
"success_url": null,
"collect": ["name", "phone"],
"created": "2026-09-16T09:14:02.118Z"
}Send url to the payer. The price is fixed: a payer cannot decide what to pay on a link. For a balance somebody pays down over time, issue a bill.
Every open reusable link is also listed on your business's page at https://pay.pamopay.co/s/{handle} — one address for a bio or a profile, where a customer chooses what to pay for. A closed, sold-out, expired or single-use link is not on it. The handle is on the dashboard's Checkout screen; the page opens once the business is live.
Knowing who paid
Twenty people buying the same item from one link are twenty identical payments, told apart by a reference you chose and an approval from the network. collect makes the page ask the buyer who they are, so the payment can say.
- Whatever you list is required of the buyer. There is no optional: a name you asked for and did not get is the same payment you had before.
- The page tells them. Beside the fields it says that your business will see what they typed, in words about you. That sentence is what makes keeping it something they agreed to, and it is not removable.
- A prompt's number stands in for
"phone". Somebody paying by mobile-money prompt is already giving the number they are paying from, so the page asks for no second one — unless they type another, which wins, since a person paying for their sister is reachable on their own phone. A bank-app payment leaves no number behind, so there the page asks. - It comes back as
payer, on the charge and oncharge.succeeded, as one object —{ "name": "Neema Mushi", "phone": "+255712345678", "email": null }— ornullwhen nobody was asked. A field the link did not ask for isnulland is never recorded, even if the page sent one. - It is not the number the payment came from. That belongs to the provider and is never returned.
phoneis the one the buyer chose to give you. - No address is verified.
emailis checked for shape only. Nothing here confirms it belongs to the buyer. - It applies to payments made after the change. Changing
collecton the next link affects nobody who has already paid.
Refusals: BAD_AMOUNT, BAD_REQUEST (title, max_uses, expiry, collect), NO_REGISTERED_WEBSITE, BAD_RETURN_URL.
GET /v1/payment_links/{id} · GET /v1/payment_links
Read them back. The list takes limit only, newest first. Closing a link is done from the dashboard.