The full API is published as an OpenAPI 3.1 document. It is the contract: if this document and the prose in these guides ever disagree, the document is correct. Generate a client from it, validate your payloads against it in CI, and diff it between releases.
Stable URLs
https://api.webrabbitmedia.com/openapi.json— served by the API edge, withETagand a 5-minute cache.https://api.webrabbitmedia.com/openapi.yaml— same document, YAML.https://webrabbitmedia.com/openapi.jsonandhttps://webrabbitmedia.com/openapi.yaml— identical mirrors served with the site.
Both URLs are unauthenticated, CORS-open and permanent. The document version is a date stamp in info.version and is echoed in the x-openapi-version response header.
What it covers
- Payments — health,
/v1/me, mobile money collections, hosted checkout, transaction list and retrieve, and the retired payout routes. - Messaging — SMS campaigns, delivery reports, one-time passcodes, wallet balance and voice, under their own
serversentry. - Webhooks — every event type, declared with OpenAPI 3.1
webhooks, one schema and one concrete example each, plus the signature headers. - Errors — a single shared error envelope with per-status examples.
required and nullable types. So: fee_amount and net_amount are always present numbers — on a pending charge fee_amount is 0 and net_amount equals gross_amount, because the platform fee is only assessed on approval. account_name is always present on a 2xx collection response, because the wallet lookup must succeed before any debit is attempted — it is absent only on the 422 account_not_found response. provider_transaction_id, code and reason are present but nullable.Generate a client
npx openapi-typescript https://api.webrabbitmedia.com/openapi.json -o src/webrabbit.d.tsDiff it in CI
Pin the version you built against and fail your pipeline when it moves, so a contract change is something you read before it reaches production.
PINNED=2026.09.08
LIVE=$(curl -sfI https://api.webrabbitmedia.com/openapi.json | tr -d '\r' | awk -F': ' '/^x-openapi-version/{print $2}')
[ "$PINNED" = "$LIVE" ] || { echo "Web Rabbit API contract changed: $PINNED -> $LIVE"; exit 1; }Official TypeScript SDK
A thin, dependency-free client is published in the repository under packages/webrabbit-node. It wraps the same contract with typed methods, idempotency keys, attribution headers, a typed error class, and a webhook signature verifier.
import { WebRabbit } from '@webrabbit/node'
const wr = new WebRabbit({
apiKey: process.env.WEBRABBIT_SECRET_KEY!,
site: 'https://manyexpress.com',
appName: 'Many Express',
})
const charge = await wr.collectMomo(
{ amount: 10, subscriber_number: '0240000000', network: 'MTN', desc: 'Trip WR-1042' },
{ idempotencyKey: 'trip-1042' },
)
if (charge.status === 'pending') {
const latest = await wr.getTransaction(charge.transaction_id)
console.log(latest.status)
}Change policy
Additive changes — new optional request fields, new response fields, new webhook event types — ship without notice, so treat unknown fields and unknown event types as safe to ignore. Anything that removes or renames a field, or changes the meaning of an existing one, is announced first in the API changelog, which is dated and separate from product release notes.
Reading the docs without a browser
Every page on this site is also published as plain Markdown, so the docs can be fetched, diffed, piped into your own tooling, or read offline with no JavaScript:
https://webrabbitmedia.com/docs/<page>.md— one file per page (e.g./docs/webhooks.md).https://webrabbitmedia.com/llms.txt— index of every page.https://webrabbitmedia.com/llms-full.txt— the entire documentation set in one file.
Both llms.txt and llms-full.txt are served from the site root and from /docs/ — https://webrabbitmedia.com/docs/llms-full.txt resolves to the same document. Neither path ever returns the application shell.
curl -s https://webrabbitmedia.com/docs/webhooks.md | less