Globpay Docs
Merchant API v1 · Multi-country

One API for pan-African payments

Globpay is a multi-country, multi-currency payment platform. Pass currency + operator (what the customer uses). Always discover enabled markets with GET /v1/operators.

Production · api.globpay.app/api/v1

Mental model

Two fields you control on every payment. Globpay routes to the right rail for that market.

LayerFieldMeaningExamples
Currency / country currency Local money unit TZS, KES, UGX, MWK, BWP, GHS, XOF, XAF, CDF, NGN, RWF, ZAR
Operator operator Brand / network the customer uses mpesa, mpesake, airtelke, yc_ug_momo
Customer pays with M-Pesa Kenya │ ▼ currency = KES operator = mpesake ← you pass this to Globpay
Wallets are per operator and currency. A KES disbursement uses your Kenya disbursement wallet — not TZS. Do not sum balances across currencies.

Markets & currencies

One Globpay API covers all markets below. Use the operator + currency for that country. New markets appear in GET /v1/operators when enabled for your account.

CurrencyCountryPhone prefix OperatorsCollection UXStatus
TZSTanzania255 mpesa, tigopesa, airtelmoney, halopesa USSD push Live
KESKenya254 mpesake, airtelke, pesalink STK Push / Airtel prompt / bank Live
UGXUganda256 yc_ug_momo MoMo prompt Live
MWKMalawi265 yc_mw_momo MoMo prompt Live
BWPBotswana267 yc_bw_momo MoMo prompt Live
GHSGhana233 tp_gh_mtn MoMo prompt Live
XOFCI / BF / TGcountry dial tp_ci_*, tp_bf_*, tp_tg_tmoney MoMo prompt; tp_ci_wavepayment_url redirect Live
XOFMali223 swychr_ml_orange, swychr_ml_moov, swychr_ml_wave MoMo prompt (Swychr — not TransactPay) Live
XOFBenin229 swychr_bj_mtn, swychr_bj_moov MoMo prompt (Swychr — not TransactPay) Live
XOFNiger227 swychr_ne_airtel MoMo prompt (Swychr) Live
GNFGuinea (Conakry)224 swychr_gn_mtn, swychr_gn_orange MoMo prompt (Swychr; Wave not available) Live
XAFCongo-Brazzaville242 swychr_cg_mtn, swychr_cg_airtel MoMo prompt (Swychr) Live
XAFGabon241 swychr_ga_airtel, swychr_ga_moov MoMo prompt (Swychr) Live
XAFCameroon237 tp_cm_mtn, tp_cm_orange MoMo prompt Live
CDFDRC243 tp_cd_airtel, tp_cd_orange, tp_cd_mpesa MoMo prompt Live
NGNNigeria234 tp_ng_bank, yc_ng_momo Bank transfer VA / P2P Live
RWFRwanda250 yc_rw_momo MoMo prompt Live
ZARSouth Africa27 yc_za_momo EFT Live
XOFSenegal221 hayb_sn_orange, hayb_sn_wave, hayb_sn_free Wallet prompt / checkout redirect Live
USDGlobal / US VA glideswipe Virtual account Planned

Phone & money rules

  • Prefer full international digits without + (e.g. 256782674977, 254712345678).
  • Local numbers starting with 0 are rewritten from currency (e.g. 0712… + KES254712…).
  • Amounts are in the local currency of the operator — no FX on collection/disbursement.
  • Minimums vary by market (e.g. Uganda MoMo often 15,000 UGX; Malawi MoMo often 5,000 MWK; Botswana MoMo often 150 BWP).

Authentication

Every request needs API key headers. Generate keys in Dashboard → Settings → API Keys. Optionally whitelist server IPs.

HeadersX-API-Key: <your_api_key> X-API-Secret: <your_api_secret> Content-Type: application/json

Quick start

  1. Create a Globpay merchant account and get API keys.
  2. GET /v1/operators — see which countries / currencies / operators your account can use.
  3. Collect or disburse with POST /v1/collection or POST /v1/disbursement — include currency.
  4. Listen for webhooks and poll GET /v1/status/{request_ref}.
  5. Credit your user only after status=completed (never on webhook alone).

Tanzania mobile money

M-Pesa / Tigo / Airtel / HaloPesa in Tanzania (TZS). Customer gets a USSD prompt.

CurrencyTZS
Phone255XXXXXXXXX (12 digits)
Operatorsmpesa, tigopesa, airtelmoney, halopesa

Collect (USSD push)

POST /v1/collection
JSON{ "phone": "255712345678", "amount": 10000, "currency": "TZS", "operator": "mpesa", "reference": "ORDER-001", "callback_url": "https://yourapp.com/webhooks/globpay" }
cURLcurl -X POST https://api.globpay.app/api/v1/collection \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Content-Type: application/json" \ -d '{"phone":"255712345678","amount":10000,"currency":"TZS","operator":"mpesa","reference":"ORDER-001"}'

Response includes request_ref and status: "processing". Flow: processing → customer confirms USSD → completed | failed.

Disburse

POST /v1/disbursement
JSON{ "phone": "255712345678", "amount": 5000, "currency": "TZS", "operator": "mpesa", "reference": "PAYOUT-TZ-001" }

Kenya mobile money

M-Pesa Kenya (KES). Globpay sends an STK Push (Lipa na M-Pesa prompt) — not manual paybill by default.

Operatormpesake
CurrencyKES
Phone2547XXXXXXXX

Collect (STK Push)

POST /v1/collection
JSON{ "phone": "254700207149", "amount": 10, "currency": "KES", "operator": "mpesake", "reference": "ORDER-KE-001" }
cURLcurl -X POST https://api.globpay.app/api/v1/collection \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Content-Type: application/json" \ -d '{"phone":"254700207149","amount":10,"currency":"KES","operator":"mpesake","reference":"ORDER-KE-001"}'

Keep KES wallets separate from TZS in your UI.

Disburse (KES M-Pesa)

JSON{ "phone": "254712345678", "amount": 500, "currency": "KES", "operator": "mpesake", "reference": "PAYOUT-KE-001" }

Kenya Airtel Money

Airtel Money Kenya (KES). globpay.app calls api.globpay.ai; Intouch stays on the old stack and webhooks back through .ai. Pass operator=airtelke. Do not use mpesake for Airtel numbers.

Operatorairtelke
Channelintouch_ke
CurrencyKES
Phone2547XXXXXXXX / 25410XXXXXXX (prefixes 010, 073, 0750–0756, 078)
Collection UXAirtel Money prompt — customer confirms on the phone

Collect (Airtel prompt)

POST /v1/collection
JSON{ "phone": "254733000000", "amount": 100, "currency": "KES", "operator": "airtelke", "callback_url": "https://your-server.example/webhook", "reference": "ORDER-KE-AIRTEL-001" }
cURLcurl -X POST https://api.globpay.app/api/v1/collection \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Content-Type: application/json" \ -d '{"phone":"254733000000","amount":100,"currency":"KES","operator":"airtelke","callback_url":"https://your-server.example/webhook","reference":"ORDER-KE-AIRTEL-001"}'

Auth is your Globpay merchant API key + secret. Typical 201 is status: processing. Credit your user only after webhook or GET /v1/status/{request_ref} shows completed.

Payout (NCBA B2C — same channel as M-Pesa)

Airtel Kenya collection stays on globpay.ai → Intouch. Payout uses the same NCBA B2C rail as mpesake. Still pass operator=airtelke so funds leave the Airtel Kenya disbursement wallet.

POST /v1/disbursement
JSON{ "phone": "254733000000", "amount": 100, "currency": "KES", "operator": "airtelke", "reference": "PAYOUT-KE-AIRTEL-001" }

Kenya bank transfer (PesaLink)

Pay any Kenya bank account via NCBA PesaLink. Requires bank selection (BIC) + account number + beneficiary name.

Operatorpesalink
Channelncba_alias
CurrencyKES
Limits50 – 999,999 KES · immediate · 24/7
Banks listGET /v1/merchant/ncba/banks — returns code + bic

List supported banks + BIC

GET /v1/merchant/ncba/banks

Call this before creating a PesaLink payout. Map banks[].codebank_code and banks[].bicbank_bic. Prefer rows where bic is not null.

200{ "banks": [ { "code": "EQUITY", "name": "Equity Bank Kenya", "bic": "EQBLKENA", "country": "KE" }, { "code": "KCB", "name": "KCB Bank Kenya", "bic": "KCBLKENX", "country": "KE" }, { "code": "CHOICE", "name": "Choice Microfinance Bank", "bic": "CHFIKENX", "country": "KE" } ], "count": 3, "country": "KE", "currency": "KES", "source": "local" }
cURLcurl -X GET "https://api.globpay.app/api/v1/merchant/ncba/banks" \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Accept: application/json"

Disburse to bank

POST /v1/disbursement
JSON{ "amount": 1500, "currency": "KES", "operator": "pesalink", "bank_code": "EQUITY", "bank_bic": "EQBLKENA", "account_number": "0123456789", "beneficiary_name": "Jane Mwangi", "reference": "PAYOUT-BANK-KE-001" }

Provide either bank_code or bank_bic (both accepted). Phone is not required for PesaLink.

Settle to saved bank

POST /v1/settlement
JSON{ "amount": 5000, "currency": "KES", "operator": "pesalink", "settlement_type": "bank", "bank_account_id": 12, "description": "Weekly settlement" }

Kenya bank accounts must include swift_code (use banks[].bic from the banks list). Admin approval releases the PesaLink transfer.

Senegal mobile money

Orange Money, Wave and Free Money in Senegal (XOF). Customer confirms in their wallet app or checkout page.

CurrencyXOF
Phone221XXXXXXXXX (12 digits)
Operatorshayb_sn_orange (Orange Money), hayb_sn_wave (Wave), hayb_sn_free (Free Money)

Collect

POST /v1/collection
JSON{ "phone": "221771234567", "amount": 10000, "currency": "XOF", "operator": "hayb_sn_orange", "reference": "ORDER-SN-001", "callback_url": "https://yourapp.com/webhooks/globpay", "success_url": "https://yoursite.com/pay/success", "failed_url": "https://yoursite.com/pay/failed" }
cURLcurl -X POST https://api.globpay.app/api/v1/collection \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Content-Type: application/json" \ -d '{"phone":"221771234567","amount":10000,"currency":"XOF","operator":"hayb_sn_wave","reference":"ORDER-SN-001"}'

Response may include a checkout_url — redirect the customer there to approve the payment. After checkout, the customer is returned to your success_url / failed_url (Globpay appends ?ref=…&status=success|failed). If omitted, Globpay hosted result pages are shown. Browser redirects are for UX only — confirm payment via webhook + GET /v1/status/{request_ref}.

Disburse (XOF)

POST /v1/disbursement
JSON{ "phone": "221771234567", "amount": 5000, "currency": "XOF", "operator": "hayb_sn_wave", "reference": "PAYOUT-SN-001" }

Keep XOF wallets separate from other currencies. Payouts are debited from your Senegal disbursement wallet.

West & Central Africa + Nigeria

Ghana (GHS), Côte d’Ivoire / Burkina / Togo (XOF), Cameroon (XAF), DRC (CDF), and Nigeria (NGN bank transfer). Swychr markets: Mali, Benin, Niger (XOF), Guinea (GNF), Congo-Brazzaville / Gabon (XAF). Collection on all listed rails. Disbursement on GHS, Swychr corridors, and XOF MoMo. Cameroon, DRC, and Nigeria bank VA stay collection-only. Kenya and Senegal use their own operators.

CountryCurrencyPhoneOperators
GhanaGHS233tp_gh_mtn
Côte d’IvoireXOF225tp_ci_mtn / moov / orange / wave
BF / TGXOFcountry dialtp_bf_*, tp_tg_tmoney
MaliXOF223swychr_ml_orange, swychr_ml_moov, swychr_ml_wave
BeninXOF229swychr_bj_mtn, swychr_bj_moov
NigerXOF227swychr_ne_airtel
Guinea (Conakry)GNF224swychr_gn_mtn, swychr_gn_orange
Congo-BrazzavilleXAF242swychr_cg_mtn, swychr_cg_airtel
GabonXAF241swychr_ga_airtel, swychr_ga_moov
CameroonXAF237tp_cm_mtn, tp_cm_orange
DRCCDF243tp_cd_airtel, tp_cd_orange, tp_cd_mpesa
NigeriaNGN234tp_ng_bank (bank transfer VA)

Collect — Ghana

POST /v1/collection
JSON{ "phone": "233241234567", "amount": 10, "currency": "GHS", "operator": "tp_gh_mtn", "reference": "ORDER-GH-001" }
Côte d’Ivoire (MTN MoMo){ "phone": "2250700000000", "amount": 500, "currency": "XOF", "operator": "tp_ci_mtn" }
Côte d’Ivoire Wave — redirect customer to payment_url{ "phone": "2250700000000", "amount": 500, "currency": "XOF", "operator": "tp_ci_wave", "reference": "ORDER-CI-WAVE-001" }

Wave CI note: tp_ci_wave returns payment_url / checkout_url. Redirect the customer there (hosted Wave checkout). Other CI rails (tp_ci_mtn / moov / orange) use a MoMo prompt — payment_url is null.

Cameroon{ "phone": "237670000000", "amount": 1000, "currency": "XAF", "operator": "tp_cm_mtn" }
Nigeria bank transfer{ "phone": "2348012345678", "amount": 5000, "currency": "NGN", "operator": "tp_ng_bank", "reference": "ORDER-NG-TP-001" }

Nigeria note: tp_ng_bank returns temporary account details in operator_response.bankInfo. Ask the customer to transfer the exact amount. Collection only — no TransactPay bank payout on this rail.

Disburse — Mali (Swychr) / Ghana MoMo

POST /v1/disbursement
Mali Orange (swychr_ml_orange){ "phone": "22376123456", "amount": 5000, "currency": "XOF", "operator": "swychr_ml_orange", "reference": "PAYOUT-ML-001" }
Ghana MTN{ "phone": "233241234567", "amount": 25, "currency": "GHS", "operator": "tp_gh_mtn", "reference": "PAYOUT-GH-001" }

Discover enabled tp_* codes with GET /v1/operators. Treat any channel on responses as opaque.

Other Africa markets

Uganda, Malawi, Botswana, Rwanda, Nigeria, South Africa, and more as Globpay enables them. Ghana and West/Central Africa use operators above. Same collection/disbursement API; change currency + operator + phone prefix.

CodeCountryCurrencyRail
yc_ug_momoUgandaUGXMobile money
yc_mw_momoMalawiMWKMobile money (Airtel / TNM)
yc_bw_momoBotswanaBWPMobile money (MyZaka / Orange)
yc_rw_momoRwandaRWFMobile money
yc_ng_momoNigeriaNGNP2P / bank (Yellow Card)
yc_za_momoSouth AfricaZAREFT
Use the operators listed for each country. Do not mix Tanzania / Kenya / Senegal / West-Central Africa codes across markets. Only operators returned by GET /v1/operators are enabled for your account.

Collect — Uganda

POST /v1/collection
JSON{ "phone": "256782674977", "amount": 15000, "currency": "UGX", "operator": "yc_ug_momo", "reference": "ORDER-UG-001", "callback_url": "https://yourapp.com/webhooks/globpay" }
cURLcurl -X POST https://api.globpay.app/api/v1/collection \ -H "X-API-Key: pk_live_..." \ -H "X-API-Secret: sk_live_..." \ -H "Content-Type: application/json" \ -d '{"phone":"256782674977","amount":15000,"currency":"UGX","operator":"yc_ug_momo","reference":"ORDER-UG-001"}'

Same endpoint — other markets

Malawi{ "phone": "265999123456", "amount": 5000, "currency": "MWK", "operator": "yc_mw_momo", "reference": "ORDER-MW-001" }
Botswana{ "phone": "26771234567", "amount": 150, "currency": "BWP", "operator": "yc_bw_momo", "reference": "ORDER-BW-001" }
Rwanda{ "phone": "250788123456", "amount": 1000, "currency": "RWF", "operator": "yc_rw_momo" }
Nigeria P2P{ "phone": "0123456789", "amount": 1000, "currency": "NGN", "operator": "yc_ng_momo", "network_id": "<bank-network-id>" }

Nigeria note: yc_ng_momo is bank/P2P (not MoMo). Pass the customer NUBAN in phone and the bank network_id from your enabled networks. For TransactPay temporary bank VA, use tp_ng_bank with the customer phone — see West & Central Africa + Nigeria.

Malawi / Botswana: MoMo rails — pass international phone digits (265… / 267…). Optionally pass network_id when the customer’s wallet network is known (Airtel/TNM or MyZaka/Orange).

Disburse — Malawi

JSON{ "phone": "265999123456", "amount": 5000, "currency": "MWK", "operator": "yc_mw_momo", "reference": "PAYOUT-MW-001" }

Disburse — Botswana

JSON{ "phone": "26771234567", "amount": 200, "currency": "BWP", "operator": "yc_bw_momo", "reference": "PAYOUT-BW-001" }

Disburse — Uganda

JSON{ "phone": "256782674977", "amount": 15000, "currency": "UGX", "operator": "yc_ug_momo", "reference": "PAYOUT-UG-001" }

Virtual accounts Live

Create a dedicated account number customers can pay into. Share deposit_instructions with the payer — Globpay credits your wallet when the deposit webhook arrives (no /v1/collection call per payment). Same capability as the merchant dashboard Virtual accounts tab.

ItemValue
CreatePOST /v1/virtual-accounts
List / showGET /v1/virtual-accounts, GET /v1/virtual-accounts/{vaNumber}
InvoicePOST /v1/invoice with currency KES / USD / EUR (optional payment_method: "virtual_account")
PaylinkPOST /v1/paylink with payment_method: "virtual_account"virtual_account_id is optional
NCBA banksGET /v1/merchant/ncba/banks — payer bank picker
CurrenciesKES (M-Pesa PayBill or SWIFT), USD / EUR (NCBA SWIFT)
LimitOne active VA per currency

NCBA deposit banks / PesaLink bank list

List banks supported for NCBA deposits and PesaLink payouts. Each row includes code, name, bic, and country:

GET /v1/merchant/ncba/banks
200{ "banks": [ { "code": "EQUITY", "name": "Equity Bank Kenya", "bic": "EQBLKENA", "country": "KE" }, { "code": "KCB", "name": "KCB Bank Kenya", "bic": "KCBLKENX", "country": "KE" }, { "code": "CHOICE", "name": "Choice Microfinance Bank", "bic": "CHFIKENX", "country": "KE" } ], "count": 3, "country": "KE", "currency": "KES", "source": "local" }

Optional query: ?fresh=1 bypasses cache. For PesaLink disbursements, send code as bank_code or bic as bank_bic.

Create VA

POST /v1/virtual-accounts
JSON{ "currency": "KES", "label": "Main KES collections" }
201 — share deposit_instructions with payer{ "provisioned": true, "display": "9835 - 77960476 - KES", "deposit_instructions": { "paybill": "400200", "account_number": "983577960476", "payment_steps": [ "Open M-Pesa → Lipa na M-Pesa → Pay Bill", "Business Number = paybill", "Account / BillRef = account_number (VA)" ] } }

How the payer pays (KES)

  1. M-Pesa → Lipa na M-Pesa → Pay Bill
  2. Business number = deposit_instructions.paybill
  3. Account / BillRef = deposit_instructions.account_number (the VA)
  4. Enter amount → PIN — wallet credits automatically

Or SWIFT / bank transfer: account number and payment reference = VA number; bank NCBA BANK; SWIFT CBAFKENXX; bank code 07000; account name D Bros Investment Limited. USD and EUR use SWIFT (same fields on deposit_instructions).

Invoice / paylink (auto-assign VA)

POST /v1/invoice
JSON{ "amount": 1500, "reference": "INV-0042", "currency": "KES", "payment_method": "virtual_account" }

The VA number becomes external_ref. Response includes deposit_instructions (PayBill + SWIFT). Hosted link: POST /v1/paylink with payment_method: "virtual_account" — omit virtual_account_id and Globpay creates or reuses the merchant VA.

USD rails (GlideSwipe) Planned

Separate from NCBA VAs above. USD virtual accounts / ACH payouts via operator=glideswipe are not self-serve yet.

Cards — Direct API (2D + 3DS) Live

Charge Visa / Mastercard by sending card details on your server (POST /v1/card/collection). 2D Direct: no Globpay page and no redirect — the API response is the result. 3DS Direct: same endpoint returns a 3ds_url when the issuer requires authentication.

PCI: Your servers touch PAN / CVV — typically SAQ D. Send only over HTTPS. Globpay forwards card data to the card processor and never stores PAN or CVV. If you must not touch cards, use the hosted 3DS flow instead (SAQ A) — it remains available.
ItemValue
EndpointPOST /v1/card/collection
Auth modes2d (immediate) or 3ds (3ds_url)
CurrenciesUSD, EUR, GBP, KES, …
OperatorBrandNotes
vaultpay_cardGlobpay Cards (VaultPay)Direct API; may return 3ds_url
orchestrate_cardGlobpay OrchestrateDirect PAN or hosted checkout / 3DS redirect. Confirm with GET /v1/operators.
Flow (Direct)Your checkout form │ ▼ Your server ──POST /v1/card/collection──▶ Globpay ──▶ card network │ │ ◀──── JSON (2d completed | 3ds + 3ds_url | failed) ──┘

1. Charge a card (Direct)

POST /v1/card/collection
Request{ "operator": "vaultpay_card", "amount": 49.99, "currency": "USD", "reference": "ORDER-10432", "description": "Order #10432", "first_name": "Jane", "last_name": "Doe", "email": "[email protected]", "card_number": "4242424242424242", "card_expiry_month": "01", "card_expiry_year": "2028", "card_cvv": "123", "line1": "123 Main St", "city": "New York", "state": "NY", "postal_code": "10001", "country": "US", "return_url": "https://your-site.com/checkout/return", "callback_url": "https://your-site.com/webhooks/globpay" }

Same body for Globpay Orchestrate — set operator to orchestrate_card. Confirm the operator is on GET /v1/operators.

FieldRequiredNotes
operatoryesvaultpay_card or orchestrate_card (must be enabled on your account)
amountyesDecimals allowed (min typically 2.00)
currencynoDefaults to operator currency (often USD)
first_name / last_name / emailyesCardholder identity
card_numberyesDigits only; never logged or stored by Globpay
card_expiry_monthyesTwo digits, e.g. 01
card_expiry_yearyesFour digits, e.g. 2028
card_cvvyes3–4 digits; never stored
line1 / city / state / postal_code / countrynoBilling address (recommended)
callback_urlnoPer-request webhook override
return_urlrecommendedWhere the customer returns after 3DS after 3DS Direct
Response 201 — 2D Direct approved (no redirect){ "success": true, "message": "Card payment completed (2D Direct).", "request_ref": "PAYAB12CD34EF56", "transaction_id": "txn_bY32XICH0yXnp0s7", "status": "completed", "auth_mode": "2d", "integration": "direct", "amount": 49.99, "currency": "USD", "operator_code": "vaultpay_card", "channel": "vaultpay", "checkout_url": null, "3ds_url": null }
Response 422 — declined / blocked{ "success": false, "message": "Card payment was not accepted.", "error": "Insufficient funds.", "request_ref": "PAYAB12CD34EF56", "status": "failed", "auth_mode": "2d" }

On 2D success, checkout_url / 3ds_url are null — do not send the customer to Globpay. Treat status: "completed" as success; still keep your webhook as a backup.

2. 3DS Direct (same endpoint)

When 3-D Secure is required, the response is auth_mode: "3ds" with a 3ds_url (not a Globpay page). Open that URL for the customer, then poll GET /v1/status/{request_ref} or wait for the webhook.

Response 201 — 3DS Direct challenge{ "success": true, "status": "processing", "auth_mode": "3ds", "integration": "direct", "request_ref": "PAYAB12CD34EF56", "3ds_url": "https://…/authentication/…", "checkout_url": "https://…/authentication/…" }

3. Test cards (test mode)

Card numberOutcome
42424242424242422D Direct success (immediate completed)
4000000000000002Declined
40000000000032203DS Direct required (3ds_url)
4000000000009995Insufficient funds

Cards — Hosted 3DS Live

Use this when you must not collect card data (SAQ A). The customer enters the card on a Globpay-hosted page; 3-D Secure is handled there. This path remains available even when Direct API is PCI-gated off. Prefer Direct API if your backend already collects the card.

ItemValue
Channelvaultpay / orchestrate
Operatorvaultpay_card or orchestrate_card
Auth modeHosted page + 3DS when required
EndpointPOST /v1/card/session
FlowPOST /v1/card/session ──▶ { pay_url } (your server) redirect customer ──▶ GET pay_url (Globpay-hosted card page) card + 3DS ──▶ card network return customer ──▶ your return_url?ref=&status= webhook ──▶ your callback_url (source of truth)

1. Create a card checkout session

POST /v1/card/session
Request{ "amount": 49.99, "currency": "USD", "reference": "ORDER-10432", "description": "Order #10432", "return_url": "https://your-site.com/checkout/return", "first_name": "Jane", "last_name": "Doe", "email": "[email protected]" }
FieldRequiredNotes
amountyesCharge amount (decimals allowed, e.g. 49.99)
currencynoDefaults to USD
referencenoYour order id (echoed back as external_ref)
return_urlnoWhere the customer lands after paying (bounced with ?ref=&status=)
first_name / last_name / emailnoPrefill the hosted form
callback_urlnoPer-request webhook override
expires_innoMinutes until the link expires (default 120)
Response 201{ "success": true, "request_ref": "PAYAB12CD34EF56", "payment_token": "9f8e7d…", "amount": 49.99, "currency": "USD", "status": "waiting", "pay_url": "https://login.globpay.app/pay/card/9f8e7d…" }

Redirect the customer to pay_url. After payment they return to:

Returnhttps://your-site.com/checkout/return?ref=PAYAB12CD34EF56&status=success&provider=vaultpay
Treat the return query string as a hint only. Confirm the final result server-side via GET /v1/status/{request_ref} or the webhook.

2. Card payment link (share instead of redirect)

To send a link rather than redirect inline, create a paylink with payment_method: "card":

POST /v1/paylink
Request{ "title": "Invoice #4501", "amount": 49.99, "currency": "USD", "payment_method": "card", "is_reusable": true, "redirect_url": "https://your-site.com/thanks" }

Returns a pay_url like https://login.globpay.app/p/PLAB12CD34. The customer opens it, pays by card (3DS handled), and — if redirect_url is set — is bounced back with ?ref=&status=.

3. Completion

Hosted card payments complete asynchronously via Globpay webhook. Rely on your callback_url webhook and/or GET /v1/status/{request_ref}.

List operators

GET /v1/operators

Returns only operators enabled for your account. Always discover from this endpoint — do not hardcode markets.

Response shape[ { "name": "M-Pesa Tanzania", "code": "mpesa", "country": "TZ", "currency": "TZS", "supports_collection": true, "supports_disbursement": true }, { "name": "M-Pesa Kenya", "code": "mpesake", "country": "KE", "currency": "KES" }, { "name": "Airtel Money Kenya", "code": "airtelke", "country": "KE", "currency": "KES" }, { "name": "Uganda MoMo", "code": "yc_ug_momo", "country": "UG", "currency": "UGX" } ]

Optional: GET /v1/operators/compare?currency=UGX&type=collection

Balances (multi-currency)

GET /v1/balance

Each operator has collection and disbursement wallets in its own currency. Group by currency for display and payouts.

JSON{ "wallets": [ { "operator": "M-Pesa Tanzania", "wallet_type": "collection", "available": 100000, "currency": "TZS" }, { "operator": "M-Pesa Kenya", "wallet_type": "collection", "available": 25000, "currency": "KES" }, { "operator": "Uganda MoMo", "wallet_type": "disbursement", "available": 500000, "currency": "UGX" } ] }
Top-level totals may mix numeric values across currencies. Always group wallets by currency (and wallet_type).

Core endpoints

MethodPathPurpose
GET/v1/operatorsEnabled operators for your account
POST/v1/collectionCollect (C2B)
POST/v1/disbursementDisburse (B2C)
GET/v1/status/{request_ref}Payment status
GET/v1/balanceMulti-currency wallets
GET/v1/transactionsHistory
POST/v1/invoiceInvoice / QR (KES/USD/EUR auto-assigns NCBA VA)
POST/v1/paylinkPayment link (card, virtual_account, or crypto)
POST / GET/v1/virtual-accountsCreate / list NCBA VAs + SWIFT instructions
POST/v1/card/collectionDirect API 2D + 3DS — pass card data (3DS → 3ds_url)
POST/v1/card/sessionHosted 3DS checkout (Globpay page, SAQ A — remains available)
POST/v1/transferCollection → disbursement (requires Auto Transfer on account)
GET/v1/transfersList internal transfers
POST/v1/sendUnified send (single or batch)
POST/v1/settlementBank settlement
POST/v1/settlement/usdtUSDT settlement (entitlement)
GET/v1/webhooks/{ref}Outbound webhook delivery status

Payment status

GET /v1/status/{request_ref}
JSON{ "request_ref": "PAY-A1B2C3D4E5F6", "type": "collection", "amount": 10000, "currency": "TZS", "operator": "M-Pesa Tanzania", "operator_code": "mpesa", "status": "completed" }

Internal transfer (collection → disbursement)

Requires Auto Transfer enabled on your merchant account by Globpay. Choose a collection wallet from GET /v1/balance, then move funds to the matching disbursement wallet.

POST /v1/transfer
JSON request{ "amount": 1000, "operator": "mpesake", "currency": "KES", "description": "Fund Kenya payouts" }
JSON response{ "success": true, "message": "Transfer auto-approved and executed.", "transfer": { "reference": "TRF-ABCDEF123456", "operator": "M-Pesa Kenya", "amount": "1000.00", "currency": "KES", "from": "collection", "to": "disbursement", "status": "approved" } }

operator accepts a code (mpesake) or display name (M-Pesa Kenya). List history with GET /v1/transfers.

Corridor (preview) Premium

Merchant remittance path: TZS collection balance → USDT → cross-border local fiat payout. Requires can_stablecoin and corridor features enabled on your account by Globpay.

MethodPathPurpose
POST/v1/corridor/quoteTZS → USDT quote
POST/v1/corridorStart corridor
GET/v1/corridor/{corridor_ref}Status
Execute{ "amount_tzs": 100000, "source_operator": "M-Pesa", "destination_operator": "yc_ug_momo", "destination_account": "+256782674977" }

Webhooks

Configure Dashboard → Webhook & API Keys → Callback URL (or pass callback_url per request). Globpay POSTs JSON when a payment completes or fails.

eventMeaning
payin.completedCollection succeeded
payin.failedCollection failed, cancelled, timed out or reversed
payout.completedDisbursement succeeded
payout.failedDisbursement failed, cancelled, timed out or reversed
Payload{ "event": "payin.completed", "request_ref": "PAY-A1B2C3D4E5F6", "external_ref": "ORDER-001", "operator_ref": "ABC123", "receipt_number": "QJI23FABC9", "type": "collection", "phone": "255712345678", "gross_amount": 10000, "platform_charge": 200, "operator_charge": 0, "net_amount": 9800, "currency": "TZS", "operator": "M-Pesa Tanzania", "operator_code": "mpesa", "channel": "payin", "status": "completed", "timestamp": "2026-07-11T06:00:00+00:00" }
Treat event as an opaque completion signal. Always confirm with GET /v1/status/{request_ref} before fulfilling your customer.

Signature verification

Once your account has a webhook secret, every delivery carries two headers:

HeaderValue
X-Payin-SignatureHMAC-SHA256 of the signed string, lowercase hex
X-Payin-TimestampUnix timestamp (seconds) used to build that string
Signed stringsignature = hmac_sha256(webhook_secret, timestamp + "." + raw_request_body)
PHP$raw = file_get_contents('php://input'); $expected = hash_hmac('sha256', $_SERVER['HTTP_X_PAYIN_TIMESTAMP'] . '.' . $raw, $webhookSecret); if (! hash_equals($expected, $_SERVER['HTTP_X_PAYIN_SIGNATURE'] ?? '')) { http_response_code(401); exit; } $payload = json_decode($raw, true);
Hash the raw request body exactly as received. Decoding the JSON and re-encoding it changes key order and spacing, so the signature will never match — this is the most common integration mistake.

Generate or rotate the secret in Dashboard → Webhook & API Keys → Webhook Signing Secret → Regenerate Secret, or call POST /api/account/webhook-secret/regenerate with your merchant bearer token. Until a secret exists, webhooks are delivered unsigned — the two headers are simply absent.

  • Return HTTP 200 within ~10 seconds.
  • Use operator_code + currency for analytics — not display name alone.
  • Handle idempotently: the same request_ref may be delivered more than once.

Status & errors

StatusMeaning
pendingCreated, not yet with the network
processingSent; waiting customer / network
waitingAwaiting customer payment (Kenya paybill mode)
completedSuccess — credit/debit applied
failedFailed
reversedReversed

Common HTTP codes: 401 auth, 403 entitlement/IP, 404 unknown ref, 422 validation / network reject, 429 rate limit.

Typical multi-currency mistakes

  • Wrong currency for the operator (e.g. TZS with mpesake)
  • Phone prefix not matching currency
  • Disbursing from an empty local wallet while another currency still has balance

Integration checklist

Tanzania

  • Operators: mpesa | tigopesa | airtelmoney | halopesa
  • Pass currency: "TZS", phones as 255…
  • Expect USSD; poll until completed / failed

Kenya

  • M-Pesa: operator=mpesake, currency: "KES", phones as 254… (STK Push)
  • Airtel collect: operator=airtelke (Airtel prompt, not STK)
  • Airtel payout: operator=airtelke on the same NCBA B2C channel as mpesake
  • Bank: operator=pesalink + bank_code/bank_bic + account_number + beneficiary_name (limits 50–999,999)
  • Banks list: GET /v1/merchant/ncba/banks; KE bank accounts need BIC (swift_code) for settlements
  • Keep KES wallets separate from TZS

Senegal

  • Operators: hayb_sn_orange | hayb_sn_wave | hayb_sn_free
  • Pass currency: "XOF", phones as 221…
  • Redirect to checkout_url when returned; set success_url / failed_url
  • Confirm via webhook + status poll — never trust the browser redirect alone

Rest of Africa

  • Boot with GET /v1/operators — only use returned yc_* codes
  • Map customer country → operator + currency + phone prefix
  • Respect market minimums; keep each local-currency wallet separate
  • Do not use yc_* for Tanzania or Kenya

Environments

Production
API hostapi.globpay.app
Base URLhttps://api.globpay.app/api/v1
MoneyReal
KeysLive keys from Dashboard → Settings → API Keys
Use api.globpay.app only. Do not call api.sandbox.globpay.app — that host is not provisioned.