Skip to navigation

Mobile money

Collect payments via mobile money networks
View as Markdown

Collect money from customers on mobile money. SenjaroPay sends a USSD push to the customer’s phone; they authorize with their PIN.

Create the payment, then confirm the result with a webhook. If the callback does not arrive, read the payment with payment status.

All calls are POST to https://api.senjaropay.com and require Content-Type: application/json, x-api-key, and x-api-secret.

How it works

1

Create a payment

Call create with the amount, customer phone, and customer details. Include a unique x-idempotency-key. Store data.reference.

2

Customer authorizes

The customer receives a USSD prompt on their wallet and enters their PIN.

3

Confirm the result

Prefer a webhook for the outcome. If the callback is late or missing, use payment status with the payment reference.

Authentication

HeaderRequiredDescription
Content-TypeYesapplication/json
x-api-keyYesDashboard Public Key (Authentication)
x-api-secretYesSecret key. Server-side only.
x-idempotency-keyYesA new UUID for each create request

Generate the idempotency key in your backend. Reuse it only when retrying the same create request.

import { randomUUID } from "node:crypto";
const idempotencyKey = randomUUID();
import uuid
idempotency_key = str(uuid.uuid4())

Use HTTPS from your backend only — never send keys from a browser or mobile app.

Supported networks

NetworkCountry
Airtel MoneyTZ
M-PesaTZ
Mixx by YasTZ
HalotelTZ

Create a payment

POST https://api.senjaropay.com/senjaropay/merchant/payments/create

SenjaroPay creates a pending collection and pushes USSD to phone_number. The session expires at data.expires_at if the customer does not complete payment. Do not fulfill the order while data.status is pending.

Request

{
"payment_type": "mobile",
"details": {
"amount": 1000,
"currency": "TZS"
},
"phone_number": "255700000001",
"customer": {
"firstname": "Test",
"lastname": "Customer",
"email": "test.customer@example.com",
"country": "Tanzania",
"city": "Dar es Salaam",
"address": "Sample Street"
},
"submerchant_id": "",
"webhook_url": "https://example.com/webhooks/senjaropay/mock-callback"
}
curl -sS -X POST "https://api.senjaropay.com/senjaropay/merchant/payments/create" \
-H "Content-Type: application/json" \
-H "x-api-key: ${SENJARO_API_KEY}" \
-H "x-api-secret: ${SENJARO_API_SECRET}" \
-H "x-idempotency-key: $(uuidgen)" \
-d '{
"payment_type": "mobile",
"details": { "amount": 1000, "currency": "TZS" },
"phone_number": "255700000001",
"customer": {
"firstname": "Test",
"lastname": "Customer",
"email": "test.customer@example.com",
"country": "Tanzania",
"city": "Dar es Salaam",
"address": "Sample Street"
},
"submerchant_id": "",
"webhook_url": "https://example.com/webhooks/senjaropay/mock-callback"
}'

Response

{
"status": "success",
"code": 200,
"data": {
"amount": {
"currency": "TZS",
"value": 1000
},
"api_version": "2026-01-25",
"expires_at": "2026-04-17T09:13:54.946Z",
"object": "payment",
"payment_type": "mobile",
"reference": "mock-ref-7b2a4f3e",
"status": "pending"
}
}

Request fields

FieldTypeRequiredDescription
payment_typestringYesMust be mobile
details.amountintegerYesAmount to collect, in major units
details.currencystringYesTZS
phone_numberstringYesCustomer MSISDN, digits only (example 255700000001)
customer.firstnamestringYesCustomer first name
customer.lastnamestringYesCustomer last name
customer.emailstringNoCustomer email
customer.countrystringNoCustomer country
customer.citystringNoCustomer city
customer.addressstringNoCustomer address
submerchant_idstringNoSub-merchant ID from the dashboard. See Introduction. Send "" when unused
webhook_urlstringNoHTTPS URL for payment result notifications

Errors

HTTP statusTypical error_codeWhen
400validation_errorMissing field, invalid amount, or malformed JSON
401unauthorizedMissing or invalid x-api-key or x-api-secret
403insufficient_scopeKey is valid but not allowed to create collections
{
"status": "error",
"code": 400,
"error_code": "validation_error",
"message": "amount is required"
}

If the same x-idempotency-key is reused, the API returns the previous transaction result instead of creating a new collection.

Examples on this page are mock values. Keep API keys in server-side secrets.