Ujumbe Pay API

A single REST surface for collections. Ujumbe Pay applies your fee rules, records the double-entry ledger split, and settles you separately — your integration only deals with payments.

Authentication

Mint a key pair in the merchant console. Send both headers on every request. The secret is stored only as a hash, so it is shown exactly once.

x-api-key: up_test_ab12cd34ef56
x-api-secret: sk_test_…
POST/api/public/v1/payments

Create a payment. Amounts are whole Tanzanian shillings. Pass idempotency_key to make retries safe — a repeat returns the original payment instead of a second one.

curl -X POST https://your-app.lovable.app/api/public/v1/payments \
  -H "content-type: application/json" \
  -H "x-api-key: up_test_ab12cd34ef56" \
  -H "x-api-secret: sk_test_…" \
  -d '{
    "amount": 50000,
    "currency": "TZS",
    "reference": "DNR9-2026-0413",
    "description": "DNR9 Race Registration",
    "invoice_reference": "INV-0413",
    "idempotency_key": "DNR9-2026-0413",
    "customer": { "name": "Asha Mwinyi", "phone": "0712345678" }
  }'
{
  "transaction_id": "UP-20260413-1234567",
  "status": "PENDING",
  "amount": 50000,
  "currency": "TZS",
  "status_url": "https://your-app.lovable.app/api/public/v1/payments/UP-20260413-1234567"
}
GET/api/public/v1/payments/{transaction_id}

Read a payment. Once it succeeds you also see the fee applied and your net amount — collection and revenue stay separate everywhere in the API.

{
  "transaction_id": "UP-20260413-1234567",
  "status": "SUCCESS",
  "amount": 50000,
  "fee": 1500,
  "gross": 50000,
  "merchant_amount": 48500,
  "channel": "MOBILE_MONEY",
  "succeeded_at": "2026-04-13T09:21:44.120Z"
}
POST/api/public/v1/provider-callback

Where the payment provider confirms an outcome. The raw body is signed with HMAC-SHA256 and sent as x-provider-signature; unsigned calls are rejected. Posting is idempotent, so repeated callbacks never double-count a payment.

{
  "transaction_id": "UP-20260413-1234567",
  "provider_reference": "SELCOM-8891233",
  "status": "SUCCESS",
  "channel": "MOBILE_MONEY"
}

Payment statuses

  • PENDING · created, awaiting the payer
  • SUCCESS · collected, fee applied, ledger posted
  • SETTLEMENT_PENDING · included in the next payout run
  • SETTLED · paid out to the merchant
  • FAILED / CANCELLED / EXPIRED · no money moved

No integration at all

Payment links give you a hosted checkout at /pay/<slug> with the same fee engine, ledger and settlement behind it.