POST /api/v1/collect

Initiate a mobile money collection from a customer's wallet.

✅

Building a full deposit flow? Follow the Integration Guide.

Endpoint

output.txtText
POST https://api.rohopay.com/api/v1/collect

Headers

HeaderRequiredValue
Authorization✅Bearer {api_key}
Content-Type✅application/json
Idempotency-Key✅Stable, unique per business event — see Idempotency

Request Body

response.jsonJSON
{
  "phone": "256700123456",
  "amount": 50000,
  "currency": "UGX",
  "description": "Order #1001",
  "callback_url": "https://your-app.com/webhooks/rohopay",
  "payment_method": "mobile_money"
}
FieldTypeRequiredDescription
phonestring✅256XXXXXXXXX — country code, no 0, no + (see Phone Formats)
amountinteger✅Whole currency units — 50000 is UGX 50,000. No minor-unit multiplier. Min UGX 500, max UGX 100,000,000
currencystring✅UGX, KES, TZS, or RWF (no default)
descriptionstring—Shown on your dashboard
callback_urlstring—Public http(s) URL that receives the webhook. Private / localhost addresses are refused
payment_methodstring—Defaults to "mobile_money"

Response (200 OK)

The response means the request was accepted, not that the customer paid. status is pending until the customer approves the prompt.

response.jsonJSON
{
  "success": true,
  "data": {
    "transaction_id": "01j2k3m4n5p6q7r8s9t0uvwx",
    "reference": "ref_ab12cd34ef56ab78",
    "status": "pending",
    "amount": 50000,
    "currency": "UGX",
    "commission": 500,
    "provider": "rohopay",
    "net_amount": 49500
  },
  "message": "Payment request initiated"
}
FieldDescription
referenceStore this. It matches the webhook's reference and is what you pass to GET /api/v1/transactions/{reference}
transaction_idRohoPay's internal id (also echoed in webhooks)
commissionRohoPay's commission on this collection
net_amountWhat your wallet is credited once the payment succeeds
⚠️

Never credit a customer or fulfil an order from this response. Wait for the webhook (or poll) to report status: "successful".

Error Responses

HTTPCodeDescription
400MISSING_IDEMPOTENCY_KEYIdempotency-Key header missing (flat body: {"error", "message"})
400INVALID_REQUESTBody is not valid JSON
400INVALID_PHONEPhone is not a supported international number
400AMOUNT_TOO_LOW / AMOUNT_TOO_HIGHOutside the allowed range
400INVALID_CALLBACK_URLcallback_url must start with http:// or https://
401INVALID_API_KEYMissing, unknown, or inactive API key
403PROJECT_INACTIVEThe project behind this key is disabled
429TEST_LIMIT_EXCEEDEDTest-mode daily limit reached (10/day)
429RATE_LIMITEDToo many requests
502PROVIDER_ERRORThe payment could not be initiated — retry as a new attempt

Errors are returned in the standard envelope:

response.jsonJSON
{ "success": false, "error": { "code": "INVALID_PHONE", "message": "…" } }