Skip to content

Quickstart

Take your first transaction end-to-end in five minutes. We'll initiate a Direct Pay-In, receive the callback, and use the status endpoint as a safety net.

Looking for a runnable reference? The payalo-docs-examples repo ships three samples — .NET (Blazor), Node.js (Express + TypeScript), and Python (FastAPI) — that each wire up every endpoint with retry handling, RFC 7807 parsing, and a webhook receiver.


Before You Start

You will need:

Item Where to get it
A brand API key From your account manager. The key is bearer-style — keep it server-side and never embed it in client code.
A publicly reachable HTTPS endpoint for callbacks Your server. For local development, expose your server with a tunnelling tool (e.g. ngrok, Cloudflare Tunnel) so the gateway can reach it.
A payment method enabled for your brand Confirm with your account manager which {method} keys (e.g. mpesa-ke) are configured.

1. Initiate a Pay-In

Send a POST to the Direct Pay-In endpoint. The example below uses M-Pesa Kenya.

curl -X POST https://api.payalo.com/gateway/mmo/v2/direct/payin/mpesa-ke \
  -H "X-Api-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "amount":     { "value": 100.00, "currency": "KES" },
    "payer":      { "id": "user-42", "msisdn": "+254712345678" },
    "country":    "KE",
    "resultUrl":  "https://merchant.example.com/webhooks/payalo",
    "merchantReference": "quickstart-001"
  }'

You should get back 200 OK with the gateway's reference:

{
  "status": "pending",
  "gatewayReference": "b2p01j3abcdef0000000000000000a1b2",
  "merchantReference": "quickstart-001",
  "reconciliationReference": "quickstart-001",
  "createdAt": "2024-06-01T12:34:56+00:00"
}

Store gatewayReference immediately — it's how you'll deduplicate the callback and look up status later. The status is always "pending" here; the real outcome arrives asynchronously.


2. Receive the Callback

Some seconds to minutes later, the gateway POSTs the final result to your resultUrl. The body matches the Mmo Transaction object.

POST /webhooks/payalo HTTP/1.1
Content-Type: application/json
X-API-KEY: <your-api-key>

{
  "status": "success",
  "type": "payin",
  "flow": "direct",
  "gatewayReference": "b2p01j3abcdef0000000000000000a1b2",
  "merchantReference": "quickstart-001",
  "method": "mpesa-ke",
  "country": "KE",
  "requestedAmount": { "value": 100.00, "currency": "KES" },
  "finalAmount":     { "value": 100.00, "currency": "KES" },
  "createdAt":   "2024-06-01T12:34:56.000000Z",
  "completedAt": "2024-06-01T12:35:12.000000Z",
  "completionSource": "webhook",
  "errorCode": null,
  "errorMessage": null,
  "providerData": { "name": "mpesa", "title": "M-Pesa Kenya", "fee": { "value": 2.00, "currency": "KES" } }
}

A minimal handler:

import secrets

def handle_callback(request):
    presented = request.headers.get("X-API-KEY", "")
    if not secrets.compare_digest(presented, EXPECTED_API_KEY):
        return Response(status=401)

    payment = request.json()
    if already_processed(payment["gatewayReference"]):
        return Response(json={"status": "ok"}, status=200)

    enqueue_for_processing(payment)            # offload the slow work
    mark_as_processed(payment["gatewayReference"])
    return Response(json={"status": "ok"}, status=200)

The three things you must do:

  1. Validate X-API-KEY — constant-time comparison against the API key configured for your brand.
  2. Deduplicate by gatewayReference — the same callback can arrive more than once.
  3. Respond within 15 seconds with any 2xx status. The response body is optional and informational only (the examples above include {"status": "ok"} for clarity). Anything other than a 2xx is a failed delivery and is not retried — fall back to the status endpoint to reconcile (see Callbacks → Delivery Policy).

3. Reconcile via Status as a Safety Net

If the callback never arrives — your endpoint was down, the network dropped, the single delivery attempt failed, or the gateway's per-merchant circuit breaker was open at the time — you can pull the same transaction object directly:

curl https://api.payalo.com/gateway/mmo/v2/status/b2p01j3abcdef0000000000000000a1b2 \
  -H "X-Api-Key: <your-api-key>"

Or, if you only have your own reference:

curl https://api.payalo.com/gateway/mmo/v2/status/mref/quickstart-001 \
  -H "X-Api-Key: <your-api-key>"

Treat the gateway as the source of truth. If your local state and the gateway's state disagree, update yours to match — see Reconciliation.


What's Next