Skip to content

Developers

Collections

A collection is one payment request for one balance: a pay link and a pay code, until a date. Use it for a one-off (a trip, a deposit, a family's share). For a balance that lasts term after term, a payment number is simpler.

Create a collection

POST/api/org/v1/collections

Also at /api/school/v1/collections. 201 when made; 200 when an open one for the same externalRef and amount already exists.

externalRefstring, requiredYour own opaque id: 1 to 200 printable characters, no spaces. Never a name or an admission number.
learnerLabelstring, requiredWhat the payer sees as who it is for: initials and class, N. K., S.2. 1 to 40 characters.
termLabelstring, requiredWhat it is for, 1 to 40 characters. A school may send any text; any other organisation sends one of its descriptions.
amountMinorstring or null, requiredThe amount in whole shillings as a string, "350000"; the payer pays exactly that. null: the payer chooses any whole amount, up to 2,000,000,000 a payment.
currencystring, requiredYour organisation's currency: UGX or KES.
expiresAtstring or nullWhen it stops, as an ISO time. Default 60 days from now; at most 180; must be in the future.

Send an Idempotency-Key header (1 to 200 printable characters) to retry safely: the same key with the same body returns the same collection; the same key with another body is a 409.

Request
curl -X POST https://wellth.example/api/org/v1/collections \
  -H "Authorization: Bearer $WELLTH_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: oca-col-2026-3-ckx123-1" \
  -d '{
    "externalRef": "oca_stu_ckx123:term_2026_3",
    "learnerLabel": "N. K., S.2",
    "termLabel": "Term 3, 2026",
    "amountMinor": "350000",
    "currency": "UGX",
    "expiresAt": "2026-12-15T00:00:00Z"
  }'
201 Created
{
  "id": "col_k2m9x4q7w1z8c5v3b6n0",
  "status": "OPEN",
  "payCode": "K7QM-2WXP",
  "payUrl": "https://wellth.example/pay/s/SGS4p_Xc3cwxh1nSw0rkXAsin0AGSRn4oyXMomn2P0E",
  "qrSvgUrl": "https://wellth.example/api/school/v1/collections/col_k2m9x4q7w1z8c5v3b6n0/qr.svg",
  "amountMinor": "350000",
  "currency": "UGX",
  "paidMinor": "0",
  "expiresAt": "2026-12-15T00:00:00.000Z"
}
idstringcol_ and 20 lower-case letters and digits.
statusstringOPEN, PAID, CANCELLED or EXPIRED. An open collection past its date reads EXPIRED.
payCodestring8 characters shown as K7QM-2WXP. Print it on the statement.
payUrlstringThe pay page, /pay/s/<token>. The token is random-looking and carries no personal data. The same link comes back on every read.
qrSvgUrlstringThe QR of payUrl as SVG (below).
amountMinorstring or nullAs you sent it.
paidMinorstringPaid so far.
expiresAtstringWhen it stops.

Sending the same externalRef again

  • An open collection with the same amount: it is returned (200). Nothing new is made.
  • An open collection with another amount: the old one is cancelled (you get collection.cancelled) and a new one is made (201), with a new link and pay code. Balances change during term.
  • None open (paid, cancelled or expired): a new one is made.

Read a collection and its payments

GET/api/org/v1/collections/:id

The same shape, plus payments: every settled payment, oldest first. 404 if it isn't yours.

payments
{
  "payments": [
    {
      "wellthRef": "WP-5TR8WK3E",
      "amountMinor": "350000",
      "paidAt": "2026-11-02T08:14:51.000Z",
      "method": "MOBILE_MONEY",
      "payer": "P. K."
    }
  ]
}

method is MOBILE_MONEY, CARD, BANK, ABROAD or WELLTH_BALANCE. payer is the payer's first name and last initial as Wellth knows them (shown here as initials).

Cancel a collection

POST/api/org/v1/collections/:id/cancel

Stops the link and the pay code at once, and answers the collection (status CANCELLED). Cancelling twice is fine.

  • A paid collection: 409 “This collection is already paid.” An expired one: 409 “This collection is already expired.”
  • A family share with a payment on its way: 409, until that payment lands or fails.
  • A payment already on its way may still land after you cancel. It is booked and reported by webhook as usual.

The QR code

GET/api/org/v1/collections/:id/qr.svg

The QR of payUrl, as image/svg+xml. Needs your key, so fetch it server-side and cache it (it is sent with Cache-Control: private, max-age=3600).

Pay codes and paying

  • 8 characters from 23456789ABCDEFGHJKLMNPQRSTUVWXYZ: no 0, O, 1 or I, so nothing is misread off paper.
  • A payer signs in at your poster page /s/<handle> and types it: any case, with or without the dash or spaces. Codes are looked up only within your organisation, and 10 wrong ones in an hour stop that person for the hour.
  • With an amount, the payer pays exactly what is left, in one payment, and the collection becomes PAID. A payment on its way (by phone or from abroad) holds it, so two people can't both pay it.
  • With any amount, it stays OPEN, taking payments, until it expires or you cancel it.
  • A bank transfer that arrives after someone else paid is still booked (so paidMinor can pass amountMinor) and held for review: Tall Grass sorts out the refund, and your finance staff are told.