UltranerDevelopersGet startedOne API for mobile money, cards, and PayPal across Africa, with a sandbox from the first minute.
14 markets · 18 networks · one endpoint · no contract
curl https://api.ultraner.com/v0/payments/charge \
-H "X-API-Key: uk_test_..." \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"currency": "TZS",
"phone": "255700000000"
}'No network parameter. The number decides the network, the country decides the gateway.
Four integrations, four sandboxes, four sets of credentials, and a launch date that keeps moving.
Charge a phone number and Ultraner works out the network, the country and the gateway behind it. Adding a market later is a new option in your dropdown, not a new integration.
A uk_test_ key on a -sandbox URL simulates the whole flow, callbacks included, and never touches a real gateway, real money, or your live webhooks. Going live is deleting -sandbox and swapping the key.
Node, Python, Go, PHP, Dart and C, a WooCommerce plugin, an OpenAPI spec, and an MCP server so your coding agent can call the API itself.
Sign up, create a test key, no verification in the way.
One POST, a simulated prompt, a webhook at your endpoint.
Checkout, callbacks and reconciliation, all against the sandbox.
The live key and the URL. Nothing else in your code changes.
curl https://api.ultraner.com/v1/disbursements \
-H "X-API-Key: uk_live_..." \
-H "X-Signature-Key: usig_live_..." \
-H "Idempotency-Key: payout-2026-09-16-0042" \
-H "Content-Type: application/json" \
-d '{
"network": "Mpesa",
"account_number": "255700000000",
"amount": 50000,
"currency": "TZS"
}'Most gateways let a timed-out payout leave you guessing whether the money moved. Here, the idempotency key is required, so a retry returns the original response. The signature key names the person who authorized it, and stops working the moment they lose that permission.
Read the payout docsSigned with HMAC-SHA256 over the raw body, retried with backoff, and every attempt visible in your request logs with the response we got back. There is a beginner walkthrough with the same code in Node, Python, PHP, Ruby and Go.
How to receive a webhookimport crypto from "crypto";
app.post("/webhooks/ultraner", express.raw({ type: "*/*" }), (req, res) => {
const signature = req.header("x-ultraner-signature");
const expected = crypto
.createHmac("sha256", process.env.ULTRANER_WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
// Constant time: a plain === leaks the secret one byte at a time.
const ok = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body);
if (event.type === "payment.success") fulfil(event.data);
// Answer fast. Anything slow belongs in a queue, not in here.
res.sendStatus(200);
});Every rail has a sandbox twin, callbacks included. Test keys never reach a real gateway, and a live key on a sandbox URL is rejected rather than quietly charging somebody.
HMAC-signed, retried with backoff, and every delivery attempt visible with its response body when something goes wrong at 2am.
Send the same Idempotency-Key twice and you get the first response back, not a second payout. Required on every payout endpoint.
Scope a key to what your integration actually does. Money leaving over the API carries a signature naming the human behind it.
A real spec for code generation, and a plain-text mirror of the docs you can paste straight into a model.
Node, Python, Go, PHP, Dart and C, a WooCommerce plugin, and npx @ultraner/mcp so your coding agent can call the API itself.
An OpenAPI spec, an llms.txt, the whole reference as plain text, and an MCP server so an agent can create payments, refunds, checkout sessions and webhooks directly. Most integrations now start in a coding tool, so the surface is shaped for one.
Add to your agent
npx @ultraner/mcp # then, in your editor "Add Ultraner checkout to this app, handle the webhook, and test it against the sandbox."
Create an account, take a sandbox key, and make your first charge in minutes. No contract, no sales call, and no waiting on verification to start building.
Choose which networks are offered, point a webhook at your own server, and use the SDK or the MCP server so your coding agent can write the integration with you.
Verification and one approved domain turn the sandbox integration into a live one. The only change to your code is the key and the URL.
Going from a sandbox key to a live payment, written for someone who has never touched a mobile money API.
Every rail has a sandbox twin. Add -sandbox to the version segment of the URL and use a uk_test_ key. The URL and the key have to agree, so a live key on a sandbox URL is rejected rather than quietly charging someone.
A verified business, an approved domain, and a live key tied to that domain. The sandbox needs none of it, so the integration can be finished while verification is still in review.
A payout carries two extra headers: X-Signature-Key, which names the person authorizing it, and Idempotency-Key, so a retry after a timeout replays the original response instead of paying twice.
That is what /ai is for: an OpenAPI spec, llms.txt, a plain-text mirror of the docs, and an MCP server (npx @ultraner/mcp) that lets an agent create payments, refunds, checkout sessions and webhooks directly.
Your operation
Live this week, not next quarter.
One payment layer for the way the people you deal with already move money.
Your next move
Start in the sandbox. Go live when you are ready.
Test keys work from the first minute and never touch real money, real gateways, or your live webhooks.
Other ways people use Ultraner