UltranerUltranerGet started
For developers and technical founders

Ship payments in an afternoon, not a quarter.

One 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.

What you would otherwise build

Every mobile money network has its own docs, its own onboarding, its own quirks, multiply that by every country you want to support.

Four integrations, four sandboxes, four sets of credentials, and a launch date that keeps moving.

01

One API for every network we are connected to

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.

02

Sandbox mode from day one

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.

03

SDKs in your language, real examples, not just reference docs

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.

Time to first payment

Nothing between you and a working charge.

Minute 1

Sandbox key in hand

Sign up, create a test key, no verification in the way.

Minute 5

First simulated payment

One POST, a simulated prompt, a webhook at your endpoint.

Day 1

The integration is done

Checkout, callbacks and reconciliation, all against the sandbox.

Go live

Swap two strings

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"
  }'
Money out, taken seriously

A payout should be hard to send twice, and easy to trace.

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 docs
Callbacks

A webhook you can verify in nine lines.

Signed 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 webhook
import 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);
});
On day one

The things you only miss at 2am.

A sandbox that behaves

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.

Signed webhooks with retries

HMAC-signed, retried with backoff, and every delivery attempt visible with its response body when something goes wrong at 2am.

Idempotency on money-out

Send the same Idempotency-Key twice and you get the first response back, not a second payout. Required on every payout endpoint.

Scoped keys, signed payouts

Scope a key to what your integration actually does. Money leaving over the API carries a signature naming the human behind it.

OpenAPI, llms.txt, docs as text

A real spec for code generation, and a plain-text mirror of the docs you can paste straight into a model.

SDKs and an MCP server

Node, Python, Go, PHP, Dart and C, a WooCommerce plugin, and npx @ultraner/mcp so your coding agent can call the API itself.

If an agent is writing it

Built to be integrated by a model, not just by a person.

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."
Claude CodeCursorCopilotWindsurf
How it works

Three steps, and you are collecting.

1Connect

Take a key, call one endpoint

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.

2Customize

Wire it into your product

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.

3Get paid

Swap the key, go live

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.

Already shipping on the Ultraner API

AtheriesBiteko StadiumCraughtDoordropDropzoniTroodKanuniLui
Free guide for developers

The Africa payments integration guide

Going from a sandbox key to a live payment, written for someone who has never touched a mobile money API.

  • Choosing between the universal checkout and a direct rail
  • Webhook verification, retries and idempotency
  • What verification actually asks for before you go live

One email with the guide. We will not add you to a drip campaign, and there is nothing to unsubscribe from.

Questions, answered

Make the next move clear.

How do I test without moving real money?+

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.

What do I need before I can take a live payment?+

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.

How do payouts work over the API?+

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.

Can an AI agent integrate this for me?+

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