Payed · Payments API v1
Payed Payments API
Take payments by mobile money (Orange Money, SMEGA) or card with one API. Create a payment, check its status, and get the result on your webhook.
Create Payment
POST/payments
One call creates the payment and starts it. Choose the method with method, then send the fields for mobile money or card below.
| Field | Type | |
|---|---|---|
amount | number | Required. In pula, e.g. 92.00. |
currency | string | BWP. |
description | string | Required. What the customer is paying for, up to 160 characters. |
reference | string | Your own id for the payment, up to 64 characters. One payment per reference. |
metadata | object | Anything you want back with the payment and in webhooks, up to 4,000 characters. |
method | string | Required. orange_money or smega (mobile money), or card. |
Mobile Money orange_money smega
The customer gets a payment request on their phone and approves it with their PIN. You learn the result from your webhook or from Payment Status.
| Field | Type | |
|---|---|---|
method | string | orange_money or smega. |
phone | string | Required. The customer's mobile money number, e.g. 73251730. |
Request
Response 201
{
"action": {
"type": "approve_on_phone",
"message": "Check your phone (73251730): approve the SMEGA payment with your PIN."
},
"payment": {
"reference": "PW1A2B3C4D5E6F",
"kind": "payment",
"status": "pending",
"amount": 92.0,
"currency": "BWP",
"description": "Order INV-1001",
"method": "smega",
"provider": "smega",
"channel": "api",
"orderRef": null,
"failure": null,
"createdAt": "2026-10-26T14:20:05Z",
"paidAt": null,
"env": "live",
"merchantReference": "INV-1001",
"metadata": {
"customerId": "C-381"
},
"fee": null,
"net": null
}
}Card card
Send the customer to action.url, their bank's 3-D Secure page. When they've confirmed, they come back to your return_url with ?payment=…&status=…. Treat the payment as paid only when your webhook or Payment Status says paid.
| Field | Type | |
|---|---|---|
method | string | card. |
name | string | Required. Name on the card. |
number | string | Required. Card number. |
month, year | number | Required. Expiry, e.g. 12 and 2030. |
cvv | string | Required. The 3 or 4 digits on the back. |
phone | string | Required. The customer's mobile number. |
return_url | string | Where the customer lands after the bank. |
Request
Response 201
{
"action": {
"type": "redirect",
"message": "Confirm the payment with your bank.",
"url": "https://checkout.tingg.africa/3ds/…"
},
"payment": {
"reference": "PW9C8B7A6F5E4D",
"kind": "payment",
"status": "pending",
"amount": 92.0,
"currency": "BWP",
"description": "Order INV-1002",
"method": "card",
"provider": "tingg",
"channel": "api",
"orderRef": null,
"failure": null,
"createdAt": "2026-10-26T14:20:05Z",
"paidAt": null,
"env": "live",
"merchantReference": "INV-1002",
"metadata": null,
"fee": null,
"net": null
}
}Payment Status
GET/payments/{REF}
The payment as it stands. While it's pending, each call checks with the provider. Replace {REF} with the payment's reference.
Request
Response 200
{
"reference": "PW1A2B3C4D5E6F",
"kind": "payment",
"status": "paid",
"amount": 92.0,
"currency": "BWP",
"description": "Order INV-1001",
"method": "smega",
"provider": "smega",
"channel": "api",
"orderRef": null,
"failure": null,
"createdAt": "2026-10-26T14:20:05Z",
"paidAt": "2026-10-26T14:21:40Z",
"env": "live",
"merchantReference": "INV-1001",
"metadata": {
"customerId": "C-381"
},
"fee": 1.38,
"net": 90.62
}| status | Meaning |
|---|---|
pending | Waiting for the customer to approve or finish paying. |
paid | Confirmed with the provider. fee and net show Payed's fee and what is owed to you. |
failed | Declined; failure says why. Create a new payment to try again. |
cancelled | Cancelled before it was paid. |
Cancel Payment
POST/payments/{REF}/cancel
Cancels a payment that hasn't been paid. A paid payment is left as it is.
Request
Response 200
{
"ok": true,
"payment": {
"reference": "PW1A2B3C4D5E6F",
"kind": "payment",
"status": "cancelled",
"amount": 92.0,
"currency": "BWP",
"description": "Order INV-1001",
"method": "smega",
"provider": "smega",
"channel": "api",
"orderRef": null,
"failure": null,
"createdAt": "2026-10-26T14:20:05Z",
"paidAt": null,
"env": "live",
"merchantReference": "INV-1001",
"metadata": {
"customerId": "C-381"
},
"fee": null,
"net": null
}
}Webhooks
Payed sends each payment's result to your server as soon as it's known, so you don't have to keep checking.
PUT/webhook
Set the address that receives your webhooks. The response gives your signing secret: keep it with your API key. Send "rotate_secret": true to get a new one, or an empty url to stop webhooks.
Request
Response 200
{
"url": "https://your-server.example/payed-webhook",
"secret": "whsec_Dj6O…",
"events": [
"payment.paid",
"payment.failed"
]
}Receive webhooks
Each webhook is a POST to your address with the header X-Payed-Signature: the HMAC-SHA256 of the raw body, keyed with your secret. Check it before trusting the webhook, then answer 200. We retry up to three times if you don't. Replace {PAYED_WEBHOOK_SECRET} with your secret.
Receiver
Transaction details
The body of every webhook:
{
"event": "payment.paid",
"payment": {
"reference": "PW1A2B3C4D5E6F",
"kind": "payment",
"status": "paid",
"amount": 92.0,
"currency": "BWP",
"description": "Order INV-1001",
"method": "smega",
"provider": "smega",
"channel": "api",
"orderRef": null,
"failure": null,
"createdAt": "2026-10-26T14:20:05Z",
"paidAt": "2026-10-26T14:21:40Z",
"env": "live",
"merchantReference": "INV-1001",
"metadata": {
"customerId": "C-381"
},
"fee": 1.38,
"net": 90.62
}
}
| Field | |
|---|---|
event | payment.paid or payment.failed. |
payment.reference | Payed's id for the payment. |
payment.merchantReference | Your reference from Create Payment. |
payment.status | paid or failed. |
payment.amount, currency | What the customer paid. |
payment.fee, net | Payed's fee, and the amount owed to you. |
payment.method, provider | How they paid: orange_money, smega or card, and through which provider. |
payment.metadata | What you sent with Create Payment. |
payment.failure | Why it failed (failed payments only). |
payment.paidAt | When it was paid (UTC). |
payment.env | test (staging key) or live. |