Early access — The API design and field names shown below reflect our current intent and may change before general availability. We’ll notify registered developers of any breaking changes.

Get notified

Let customers buy now, pay later — right at your counter.

One API call to initiate. One webhook to confirm. Works on every phone in Zambia — no app, no QR code.

REST APIEarly AccessUSSD PushHMAC-SHA256
< 90sapproval time
2 callsto integrate
any phonevia USSD push
Traditional terminal

Traditional terminal

Works with any device that can make an HTTPS call

From API call to approved in 4 steps

Everything your POS software needs to do — nothing more.

01

Get your credentials

Sign up for sandbox access. Your dashboard issues a Bearer token and merchant ID instantly — no manual approval.

sandbox.usetupane.com
02

Initiate the checkout

Send the customer's phone number, your merchant ID, and the order total. The API returns the full payment split within milliseconds.

POST /v1/pos/checkout
03

Display split, await approval

Render the 25% downpayment and 3 installments on your till screen. The customer approves via USSD on their own phone — no app required.

GET /v1/pos/checkout/{id}
04

Confirm and complete

A webhook fires the moment status reaches COMPLETED. Release the goods and record the transaction reference. Integration complete.

webhook: pos.checkout.completed

One transaction.
Four structured payments.

Every checkout response includes the full payment schedule. Your POS renders it at the till before the customer enters their PIN — complete transparency, zero ambiguity.

Order totalZMW 1,500.00
DownpaymentAt the counter
25%
Installment 1Week 1 / Month 1
25%
Installment 2Week 2 / Month 2
25%
Installment 3Week 3 / Month 3
25%

Installments are auto-deducted from the customer’s mobile money wallet on schedule.

API reference

Base URLhttps://api.usetupane.comSandboxhttps://sandbox.usetupane.com
POST/v1/pos/checkout

Initiate checkout

Triggers a USSD push to the customer’s phone immediately. The response includes the full payment schedule — render it on your POS screen before the customer confirms.

merchant_idstringrequired

Your Tupane merchant identifier.

customer_phonestringrequired

Customer’s mobile number in international format (e.g. 260977…).

order_totalintegerrequired

Total in Zambian Ngwee. 100 ngwee = ZMW 1.

installment_frequency"weekly" | "monthly"

Repayment cadence. Defaults to "weekly".

POST /v1/pos/checkout HTTP/1.1Host: api.usetupane.comAuthorization: Bearer <merchant_token>Content-Type: application/json{  "merchant_id": "TPN_XXXXXX",  "customer_phone": "260977123456",  "order_total": 150000,  "installment_frequency": "weekly"}

GET/v1/pos/checkout/{session_id}

Poll for result

Poll every 5 seconds until status leaves PENDING_APPROVAL. Sessions expire after 90 seconds.

PENDING_APPROVALKeep spinner running
COMPLETEDShow receipt — loan_id populated
DECLINEDOffer retry or alternative payment
EXPIREDStart a new checkout session
GET /v1/pos/checkout/3f2d9a... HTTP/1.1Host: api.usetupane.comAuthorization: Bearer <merchant_token>

WEBHOOKpos.checkout.completed

Receive a webhook instead

Configure a webhook URL in your merchant dashboard. Tupane will POST the confirmation the moment the customer approves — no polling required.

All callbacks are signed with HMAC-SHA256. Always verify the X-Tupane-Signature header before processing any payload.

POST https://your-pos.example.com/webhook HTTP/1.1X-Tupane-Signature: sha256=<hmac_hex>Content-Type: application/json{  "event": "pos.checkout.completed",  "session_id": "3f2d9a...",  "loan_id": 4821,  "merchant_id": "TPN_XXXXXX",  "order_total_ngwee": 150000}

ERRORS

Error responses

All errors return JSON with an error field. 503 is safe to retry — all others require a corrected request.

400Customer has an active repayment plan already
400Order total exceeds customer’s available credit limit
404Phone number not registered with Tupane
503Could not reach customer’s network — retry safe

Error shape

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "ACTIVE_PLAN_EXISTS",
  "message": "Customer already has an active repayment plan."
}

Works with any POS stack

If your POS can make an HTTPS request, it can use Tupane. Native SDKs and plugins are on the way.

Coming soon

REST API

Any language, any platform. If you can make an HTTP call, you’re done.

Coming soon

JavaScript / Node.js SDK

Promise-based wrapper with full TypeScript types. Drop-in for any Node backend.

Coming soon

Android POS plugin

Purpose-built for Android-based POS terminals. Single AAR dependency.

Roadmap

Odoo / ERPNext module

Native Tupane checkout inside your ERP — no custom code required.

Secure by design

No customer credentials pass through your POS. Every call is authenticated, every webhook is signed.

Bearer token auth

Merchants authenticate with a short-lived JWT. Customer credentials are never exposed to the POS system.

PIN stays on the customer’s phone

The mobile money PIN is entered on the customer’s own device. It never touches your POS hardware or network.

HMAC-SHA256 webhooks

Every callback is signed with your secret. Verify X-Tupane-Signature before processing any payload.

90-second session expiry

Checkout sessions auto-expire. No dangling approvals, no replay attacks.

Full audit trail

Every transaction is logged with a tamper-evident record. Session IDs, loan IDs, and timestamps on every event.

TLS 1.2+ everywhere

All API traffic is encrypted in transit. There are no plain HTTP endpoints.

From zero to live in an afternoon

Sandbox access is instant. No telco agreement, no real money required until you’re ready.

01

Get your credentials

Register at the merchant portal. Your merchant_id and API token are issued immediately — no manual approval.

02

Hit the sandbox

POST /v1/pos/checkout against sandbox.usetupane.com. Simulated USSD approval comes back in under a second.

03

Test every state

Use sandbox trigger codes to simulate COMPLETED, DECLINED, and EXPIRED — cover every branch before you ship.

04

Point to production

Change the base URL from sandbox to api.usetupane.com. Same token shape, same request body, same webhook events.

No spam. We’ll only contact you about developer access.