# Submit Card Details
Source: https://docs.payfonte.com/api-reference/card-collections/submit-card-details
/api-reference/openapi-3.1.yml post /payments/v1/cards/process
Submit customer card details to start a card payment. Sandbox card test data is available in [Testing](https://docs.payfonte.com/en/guides/introductions/testing#card-test-details).
# Submit Card OTP
Source: https://docs.payfonte.com/api-reference/card-collections/submit-card-otp
/api-reference/openapi-3.1.yml post /payments/v1/cards/otp
Submit the customer OTP when a card payment response returns `action` as `otp`. Sandbox card test data is available in [Testing](https://docs.payfonte.com/en/guides/introductions/testing#card-test-details).
# Submit Card PIN
Source: https://docs.payfonte.com/api-reference/card-collections/submit-card-pin
/api-reference/openapi-3.1.yml post /payments/v1/cards/pin
Submit the card PIN when a card payment response returns `action` as `pin`. Sandbox card test data is available in [Testing](https://docs.payfonte.com/en/guides/introductions/testing#card-test-details).
# Collection API - Direct
Source: https://docs.payfonte.com/api-reference/collections/collection-api--direct
/api-reference/openapi-3.1.yml post /payments/v1/payments/direct-charge
Charge the Customer via API
# Collections API - Generate Checkout
Source: https://docs.payfonte.com/api-reference/collections/collections-api--generate-checkout
/api-reference/openapi-3.1.yml post /payments/v1/checkouts
Generate a Payment Checkout URL for customers to make payment
# Confirm Direct Charge Customer Input
Source: https://docs.payfonte.com/api-reference/collections/confirm-direct-charge-customer-input
/api-reference/openapi-3.1.yml post /payments/v1/payments/confirm
Submit customer input, such as an OTP, when a Direct Charge response returns `action` as `otp`.
# Fetch Collection History
Source: https://docs.payfonte.com/api-reference/collections/fetch-collection-history
/api-reference/openapi-3.1.yml get /payments/v1/payments
Retrieve a paginated list of all collection transactions
# Fetch Provider Properties
Source: https://docs.payfonte.com/api-reference/collections/fetch-provider-properties
/api-reference/openapi-3.1.yml get /payments/v1/payments/direct-charge/{provider}/properties
This is the endpoint to Fetch properties for provider that needs them Direct charge API can be called. E.g Pawapay
# Verify Collection (TSQ)
Source: https://docs.payfonte.com/api-reference/collections/verify-collection-tsq
/api-reference/openapi-3.1.yml get /payments/v1/payments/verify/{reference}
This is the endpoint to verify a Transaction (TSQ)
# Fetch All Disbursements Transaction
Source: https://docs.payfonte.com/api-reference/disbursements/fetch-all-disbursements-transaction
/api-reference/openapi-3.1.yml get /billing/v1/disbursements
Retrieve a paginated list of all disbursement transactions
# Fetch Provider Properties
Source: https://docs.payfonte.com/api-reference/disbursements/fetch-provider-properties
/api-reference/openapi-3.1.yml get /billing/v1/transfer-recipients/{provider}/properties
This is the endpoint to Fetch properties for provider that needs them before a transfer recipient can be created. E.g Paystack (Bank Transfer)
# Request a Disbursement
Source: https://docs.payfonte.com/api-reference/disbursements/request-a-disbursement
/api-reference/openapi-3.1.yml post /billing/v1/disbursements
Request a Disbursement to a Transfer Recipient
# Validate A Transfer Recipient
Source: https://docs.payfonte.com/api-reference/disbursements/validate-a-transfer-recipient
/api-reference/openapi-3.1.yml post /billing/v1/transfer-recipients/validate
Create and Validate a Transfer Recipient for Disbursements
# Verify a Disbursement
Source: https://docs.payfonte.com/api-reference/disbursements/verify-a-disbursement
/api-reference/openapi-3.1.yml get /billing/v1/disbursements/verify/{reference}
Verify a Disbursement
# Fetch Activated Integrations
Source: https://docs.payfonte.com/api-reference/integrations/fetch-activated-integrations
/api-reference/openapi-3.1.yml get /integrations/v1/integrations
Retrieve payment providers that have been activated for your business. Filter the response by country, currency, and integration type.
# Create Payment Link
Source: https://docs.payfonte.com/api-reference/payment-links/create-payment-link
/api-reference/openapi-3.1.yml post /payments/v1/payment-links
Create a shareable payment link that customers can use to complete payment through hosted checkout.
# Fetch All Payment Links
Source: https://docs.payfonte.com/api-reference/payment-links/fetch-all-payment-links
/api-reference/openapi-3.1.yml get /payments/v1/payment-links
Retrieve a paginated list of payment links.
# Fetch Payment Link By ID
Source: https://docs.payfonte.com/api-reference/payment-links/fetch-payment-link-by-id
/api-reference/openapi-3.1.yml get /payments/v1/payment-links/{id}
Retrieve a payment link and its analytics by payment link ID.
# Fetch Wallets
Source: https://docs.payfonte.com/api-reference/wallet/fetch-wallets
/api-reference/openapi-3.1.yml get /billing/v1/wallets
This is the endpoint to Fetch Wallet for a business
# Collections - Card API
Source: https://docs.payfonte.com/en/guides/collections/card-api
Submit card details and continue card collections through PIN, OTP, 3DS redirect, or verification actions.
Card payments may require more than one API call before Payfonte can confirm the final outcome. The first card request returns an `action` that tells your backend what to collect or do next.
## Endpoints
| Method | Endpoint | Purpose |
| ------ | ------------------------------------------ | -------------------------------------------------------------------------- |
| `POST` | `/payments/v1/cards/process` | Submit card details and start the card payment |
| `POST` | `/payments/v1/cards/pin` | Submit card PIN when the response action is `pin` |
| `POST` | `/payments/v1/cards/otp` | Submit customer OTP when the response action is `otp` |
| `GET` | `/payments/v1/payments/verify/{reference}` | Verify final transaction status when the response action is `verification` |
## Testing
Sandbox card test data is available in [Testing](/en/guides/introductions/testing#card-test-details).
## Integration Steps
Call `/payments/v1/cards/process` with `provider`, `amount`, and `card`. You can also pass root-level `reference`, `redirectURL`, and `webhook` values for transaction tracking, customer return, and webhook override behavior. Send your client identifier in the `client-id` header.
Use `data.action` to decide whether to collect PIN, collect OTP, redirect for 3DS, or verify the payment.
Submit PIN or OTP when requested, or redirect the customer to `data.data.redirectURL` for 3DS authentication.
When the action is `verification`, call `GET /payments/v1/payments/verify/{reference}` from your backend before fulfilling the order.
## Submit Card Details
```bash theme={null}
curl --request POST \
--url https://sandbox-api.payfonte.com/payments/v1/cards/process \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'content-type: application/json' \
--data '{
"reference": "ORDER-1001",
"provider": "card-nigeria",
"amount": 50000,
"redirectURL": "https://yourapp.com/payment/complete",
"webhook": "https://yourapp.com/webhooks/payfonte",
"card": {
"pan": "5061 4604 1012 1111 102",
"expiry": {
"month": "12",
"year": "2050"
},
"cvv": "558",
"cardHolderName": "Emily Heidenreich-Kohler",
"email": "Darrick.OHara@hotmail.com",
"phoneNumber": "(536) 393-0857",
"address": "Address 1, Lokoja",
"city": "my-city"
}
}'
```
## Request Fields
| Field | Type | Required | Description |
| ------------- | ------- | ----------- | ---------------------------------------------- |
| `provider` | string | Yes | Card provider slug, for example `card-nigeria` |
| `amount` | integer | Yes | Amount in minor units |
| `card` | object | Yes | Card and customer billing details |
| `reference` | string | Recommended | Unique transaction identifier from your system |
| `redirectURL` | string | No | Customer return URL after payment |
| `webhook` | string | No | Per-transaction webhook override URL |
## Submit PIN
Use this endpoint when the previous response returns `data.action` as `pin`.
```bash theme={null}
curl --request POST \
--url https://sandbox-api.payfonte.com/payments/v1/cards/pin \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'content-type: application/json' \
--data '{
"reference": "DCD20260701144120NCDZW",
"provider": "card-nigeria",
"card": {
"pan": "5061 4604 1012 1111 106",
"expiry": {
"month": "12",
"year": "2050"
},
"cvv": "562",
"pin": "1106",
"cardHolderName": "Donna Flatley",
"email": "Darrick.OHara@hotmail.com",
"phoneNumber": "(536) 393-0857",
"address": "Address 1, Lokoja",
"city": "my-city"
}
}'
```
## Submit OTP
Use this endpoint when the previous response returns `data.action` as `otp`.
```bash theme={null}
curl --request POST \
--url https://sandbox-api.payfonte.com/payments/v1/cards/otp \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'content-type: application/json' \
--data '{
"reference": "DCD20260701144120NCDZW",
"otp": "543210"
}'
```
## Response Actions
Collect the customer's card PIN and call `POST /payments/v1/cards/pin` with the returned `reference`.
```json theme={null}
{
"statusCode": 200,
"data": {
"reference": "DCD20260701133425EIQWF",
"action": "pin",
"data": {}
}
}
```
Collect the OTP sent to the customer and call `POST /payments/v1/cards/otp` with the returned `reference`.
```json theme={null}
{
"statusCode": 201,
"data": {
"reference": "DCD20260701133425EIQWF",
"action": "otp",
"data": {}
}
}
```
Redirect the customer to `data.data.redirectURL` to complete 3DS authentication. After the redirect flow, verify the payment server-side.
```json theme={null}
{
"statusCode": 201,
"data": {
"reference": "DCD20260701144120NCDZW",
"action": "redirect",
"data": {
"redirectURL": "https://s.6bd.co/card-3ds/mce1aN"
}
}
}
```
Call `GET /payments/v1/payments/verify/{reference}` with the returned `reference` to confirm the final transaction status.
```json theme={null}
{
"statusCode": 200,
"data": {
"reference": "DCD20260701133425EIQWF",
"action": "verification",
"data": {}
}
}
```
## Flow Decision Summary
| Action | Customer next step | Merchant next step |
| -------------- | --------------------------- | --------------------------------------------------- |
| `pin` | Enter card PIN | Call `POST /payments/v1/cards/pin` |
| `otp` | Share OTP | Call `POST /payments/v1/cards/otp` |
| `redirect` | Complete 3DS authentication | Redirect to `data.data.redirectURL`, then verify |
| `verification` | No further customer input | Call `GET /payments/v1/payments/verify/{reference}` |
## Important Rules
Amount values must be integers in minor units. Decimals are not supported.
See [Amount Specification](/en/guides/introductions/amount-specification).
Collect and submit card data only from secure, PCI-compliant environments. Do not log PAN, CVV, PIN, or OTP values.
## Related Docs
View card payment endpoint definitions and request schemas.
Confirm final transaction outcomes asynchronously.
Use sandbox card data for PIN, OTP, 3DS, success, failed, and pending scenarios.
# Overview
Source: https://docs.payfonte.com/en/guides/collections/direct-charge-api
Charge customers directly from your backend using provider slugs and customer input without creating a hosted checkout session.
Direct Charge allows your backend to initiate payment directly with a provider, without first creating a checkout URL.
## When To Use Direct Charge
Best for server-to-server payment initiation where you control the full transaction lifecycle.
Use when payment requires provider-specific fields like `network` or customer OTP codes.
Useful for tightly integrated experiences where redirect checkout is not preferred.
## Endpoints
| Method | Endpoint | Purpose |
| ------ | ----------------------------------------------------------- | ---------------------------------------------------------------- |
| `GET` | `/payments/v1/payments/direct-charge/{provider}/properties` | Fetch provider-specific properties (optional for some providers) |
| `POST` | `/payments/v1/payments/direct-charge` | Initiate direct charge |
| `GET` | `/payments/v1/payments/verify/{reference}` | Verify final transaction status |
## Integration Steps
Select a valid provider from [Supported Providers](/en/guides/introductions/supported-providers).
For providers like Bank Transfer(bank-transfer-nigeria), fetch required properties (for example network values) before charging.
Call the direct-charge endpoint with `provider`, `amount`, and `customerInput`.
Use response action (`processing`, `redirect`, `bankTransfer`) and finalize based on webhook/verification.
## Fetch Provider Properties (Optional)
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/payments/direct-charge/{provider}/properties' \
--header 'client-id: ' \
--header 'client-secret: '
```
Example response:
```json theme={null}
{
"data": {
"networks": [
{ "name": "Airtel", "value": "airtel" },
{ "name": "MTN MoMo", "value": "mtn-momo" }
]
}
}
```
## Direct Charge Request
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/payments/direct-charge' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "ORDER-1001",
"amount": 10000,
"provider": "mtn-momo-ivory-coast",
"webhook": "https://yourapp.com/webhooks/payfonte",
"narration": "Order payment",
"customerInput": {
"phoneNumber": "2250512345678"
}
}'
```
Sample response:
```json theme={null}
{
"data": {
"action": "processing",
"sessionId": "1031-4120-a98f-9357692945",
"provider": "mtn-momo-ivory-coast",
"channel": "mobile-money",
"reference": "ORDER-1001",
"amount": 10000,
"status": "pending",
"statusDescription": "Awaiting Provider's Feedback"
},
"statusCode": 201
}
```
## Request Fields
| Field | Type | Required | Description |
| --------------- | ------- | ----------- | ---------------------------------------------------- |
| `provider` | string | Yes | Provider slug (for example `mtn-momo-ivory-coast`) |
| `amount` | integer | Yes | Amount in minor units (no decimals) |
| `customerInput` | object | Yes | Provider/customer fields (for example `phoneNumber`) |
| `reference` | string | Recommended | Unique merchant reference |
| `webhook` | string | No | Override webhook for this transaction |
| `narration` | string | No | Transaction description |
| `metadata` | object | No | Custom metadata returned downstream |
## Action Types and Handling
Customer/provider interaction is in progress (for example USSD/STK authorization pending).
Keep payment state pending and wait for webhook/verification final status.
Redirect customer to provider URL (usually at `data.data.link`).
Do not treat redirect completion alone as payment success.
Display returned bank transfer instructions (account name/number, amount, expiry).
Wait for webhook/verification before marking success.
## Amount Rule (Important)
Payfonte does not support decimal amounts in API requests. Send integer minor-unit values only.
* `100.00 NGN` -> `10000`
* `2500.75 NGN` -> `250075`
See [Amount Specification](/en/guides/introductions/amount-specification).
## Final Status Confirmation
For order fulfillment, rely on:
1. [Webhooks](/en/guides/collections/webhook) for async payment updates.
2. `GET /payments/v1/payments/verify/{reference}` for backend verification.
## Related Docs
Understand `processing`, `redirect`, `bankTransfer`, and pre-OTP patterns.
Copy provider-specific request examples.
Provider slugs, limits, and country coverage.
# Direct Charge Example Payloads
Source: https://docs.payfonte.com/en/guides/collections/direct-charge/examples
Copy-ready direct charge payloads for standard mobile money, Bank Transfer, and Orange pre-OTP provider flows.
Use these payload templates when calling:
`POST /payments/v1/payments/direct-charge`
## Common Payload (Most Providers)
```json theme={null}
{
"reference": "ORDER-1001",
"amount": 10000,
"provider": "mtn-momo-ivory-coast",
"webhook": "https://yourapp.com/webhooks/payfonte",
"narration": "Order payment",
"customerInput": {
"phoneNumber": "2250512345678"
}
}
```
## Orange Pre-OTP Payload
Orange providers may require a customer-generated code before request submission.
### USSD guidance
* Orange Senegal: `#144#391#`
* Orange Mali: `#144#77#`
* Orange Burkina Faso: `*144*4*6*amount#`
On sandbox, any random 6-digit code can be used for testing.
```json theme={null}
{
"reference": "ORDER-1003",
"amount": 10000,
"provider": "orange-senegal",
"webhook": "https://yourapp.com/webhooks/payfonte",
"narration": "Order payment",
"customerInput": {
"phoneNumber": "786175702",
"customerCode": "<6-digit-code>"
}
}
```
## Field Reference
| Field | Type | Required | Notes |
| ---------------------------- | ------- | ----------------- | --------------------------------------------------- |
| `reference` | string | Recommended | Must be unique per transaction |
| `amount` | integer | Yes | Minor-unit value only |
| `provider` | string | Yes | Use slug from Supported Providers |
| `webhook` | string | No | Per-request webhook override |
| `narration` | string | No | Human-readable transaction note |
| `customerInput.phoneNumber` | string | Usually Yes | Format based on provider/country |
| `customerInput.network` | string | Provider-specific | Required for some specific flows like bank transfer |
| `customerInput.customerCode` | string | Provider-specific | Required for Orange pre-OTP flows |
## Validation Checklist Before Sending
Send integer minor-unit amounts only. Decimals are not supported.
Ensure `provider` matches a valid slug from [Supported Providers](/en/guides/introductions/supported-providers).
Confirm provider-specific fields exist (`phoneNumber`, `network`, `customerCode`) before sending request.
Generate unique references to prevent duplicate transaction errors.
## Related Docs
Request flow and response/action handling.
Processing, redirect, bankTransfer, and pre-OTP behavior.
Minor-unit conversion rules for all amounts.
# Direct Charge Processing Flows
Source: https://docs.payfonte.com/en/guides/collections/direct-charge/response-types
Understand Direct Charge response types across processing, redirect, bankTransfer, pre-OTP, and OTP provider flows.
When you call the Direct Charge API, the initial response tells you how the customer should continue or what your backend should wait for. Most Direct Charge flows follow one of these response types:
* `processing` (USSD/STK prompt flow)
* `redirect` (provider-hosted completion flow)
* `bankTransfer` (customer must transfer to returned account details)
* `pre-otp` (customer code required before request)
* `otp` (customer must enter an OTP returned after request initiation)
## 1) Processing Flow (USSD/STK Prompt)
Customer receives authorization prompt on mobile device and confirms with PIN.
### What happens
1. You initiate direct charge.
2. Provider sends STK push/USSD prompt to customer.
3. Customer authorizes on device.
4. Transaction remains pending until provider final response.
### How to detect
`data.action` is `processing`.
```json theme={null}
{
"data": {
"action": "processing",
"sessionId": "1031-4120-a98f-9357692945",
"provider": "safaricom-kenya",
"channel": "mobile-money",
"reference": "DDC20250812042317DIFMW",
"amount": 1000,
"status": "pending",
"charge": 5,
"statusDescription": "Awaiting Provider's Feedback"
},
"statusCode": 201
}
```
### Merchant handling
* Show pending state to customer.
* Do not fulfill on initial response.
* Wait for webhook or verify by reference.
## 2) Redirect Flow
Provider returns a link; customer must complete payment on provider page/app.
### What happens
1. You initiate direct charge.
2. API responds with redirect URL.
3. Customer completes payment on provider channel.
4. Customer may return to your app/site afterward.
### How to detect
`data.action` is `redirect` and URL is typically in `data.data.link`.
```json theme={null}
{
"data": {
"action": "redirect",
"sessionId": "v1nadjww8lwfxxd7giumi3dyik7pzaxrxqmyvdeuunvixo25jhqf4o6wzuxhjdzg",
"provider": "orange-ivory-coast",
"channel": "mobile-money",
"reference": "DDC20250812042546ICXFC",
"amount": 10000,
"status": "pending",
"charge": 150,
"statusDescription": "Awaiting Provider's Feedback",
"data": {
"link": "https://mpayment.orange-money.com/sx/mpayment/abstract/...",
"message": "Click link to complete your payment",
"reference": "DDC20250812042546ICXFC"
}
},
"statusCode": 201
}
```
### Merchant handling
* Redirect user to `data.data.link`.
* On return, still verify final status server-side.
* Do not mark success from redirect alone.
## 3) Bank Transfer Flow
Payfonte returns bank account details; the customer must make a bank transfer to complete payment.
### What happens
1. You initiate direct charge with a bank transfer provider.
2. API responds with account details for the customer payment.
3. You display the account details to the customer.
4. Customer sends the transfer from their banking app or bank channel.
5. Transaction remains pending until provider confirmation.
### How to detect
`data.action` is `bankTransfer`. Account details are returned in `data.data`.
```json theme={null}
{
"data": {
"action": "bankTransfer",
"sessionId": "BT-20250812043010-9D7M2",
"provider": "bank-transfer-nigeria",
"channel": "bank-transfer",
"reference": "ORDER-1002",
"amount": 10000,
"status": "pending",
"charge": 100,
"statusDescription": "Awaiting customer bank transfer",
"data": {
"accountName": "PAYFONTE / Karis Clothing",
"accountNumber": "0123456789",
"bankName": "Wema Bank",
"bankCode": "035",
"amount": 10000,
"reference": "ORDER-1002",
"expiresAt": "2025-08-12T04:45:10.000Z"
}
},
"statusCode": 201
}
```
### Merchant handling
* Display the returned account details clearly to the customer.
* Include bank name, account number, account name, amount, reference, and expiry when present.
* Keep the payment pending until webhook or verification confirms final status.
* Do not fulfill on proof of transfer alone.
## 4) Pre-OTP Flow
Some providers require customer to generate a provider code/OTP before you send the charge request.
### What happens
1. Customer generates code via provider USSD.
2. Customer shares code with merchant.
3. Merchant sends `customerInput.customerCode`.
4. Provider processes charge.
### Common USSD codes
* Orange Ivory Coast: `#144*82#`
* Orange Senegal: `#144#391#`
* Orange Burkina Faso: `*144*4*6*Amount*PIN#`
* Orange Mali: `#144#37#`
### Sample request
```json theme={null}
{
"reference": "ORDER-1002",
"amount": 50000,
"provider": "orange-senegal",
"webhook": "https://yourapp.com/webhooks/payfonte",
"narration": "Direct charge test",
"customerInput": {
"phoneNumber": "786175702",
"customerCode": "758610"
}
}
```
### Merchant handling
* Collect OTP/customer code explicitly.
* Validate format before API call.
* Continue with normal webhook/verification completion flow.
## 5) OTP Flow
Some providers send an OTP to the customer after you initiate the Direct Charge request. Your application must collect that OTP from the customer and submit it to the confirmation API.
### What happens
1. You initiate direct charge.
2. API responds with `action` as `otp`.
3. Customer receives an OTP by SMS or provider channel.
4. You display an interface where the customer can enter the OTP.
5. Your backend submits the OTP with the transaction `reference`.
6. Transaction remains pending until provider final response.
### How to detect
`data.action` is `otp`. OTP instructions are returned in `data.data.message`, and `data.data.numberOfDigits` may tell you the expected OTP length.
```json theme={null}
{
"data": {
"action": "otp",
"sessionId": "DDC20260702112401ZIWGF",
"provider": "qmoney-gambia",
"reference": "DDC20260702112401ZIWGF",
"amount": 1000,
"currency": "GMD",
"totalAmount": 1000,
"status": "pending",
"charge": 0,
"data": {
"message": "You will receive an OTP via SMS on your phone number 3141106. Please provide the OTP to continue this payment.",
"numberOfDigits": 6
},
"statusDescription": "Awaiting Customer Input"
},
"statusCode": 201
}
```
### Submit customer OTP
```bash theme={null}
curl --request POST \
--url https://sandbox-api.payfonte.com/payments/v1/payments/confirm \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'content-type: application/json' \
--data '{
"reference": "DDC20260702112401ZIWGF",
"customerInput": {
"otp": "445985"
}
}'
```
### Confirmation response
```json theme={null}
{
"statusCode": 201,
"data": {
"action": "processing",
"sessionId": "cos-1z3x983b01300",
"provider": "qmoney-gambia",
"reference": "DDC20260702115234PTIFG",
"providersReference": "PIX_44241170102532681668",
"amount": 1000,
"totalAmount": 1000,
"charge": 0,
"status": "pending",
"data": {
"message": "OTP submitted successfully. Payment confirmation is processing."
},
"statusDescription": "Awaiting Provider's Feedback"
}
}
```
### Merchant handling
* Build a customer-facing OTP entry interface when `data.action` is `otp`.
* Use `data.data.numberOfDigits` to guide validation when it is present.
* Submit the OTP from your backend to `POST /payments/v1/payments/confirm`.
* Keep the payment pending until webhook or verification confirms final status.
## Flow Decision Summary
| Action | Customer next step | Merchant next step |
| ------------------------- | ------------------------------------------ | ------------------------------------------------- |
| `processing` | Approve on device (USSD/STK) | Wait for webhook/verify |
| `redirect` | Complete payment on provider page | Redirect + wait for webhook/verify |
| `bankTransfer` | Transfer to the returned account details | Display account details + wait for webhook/verify |
| `pre-otp` request pattern | Generate and share code first | Send code in `customerInput.customerCode` |
| `otp` | Enter OTP received by SMS/provider channel | Collect OTP + submit confirmation request |
## Important Rules
Amount values must be integers in minor units. Decimals are not supported.
See [Amount Specification](/en/guides/introductions/amount-specification).
## Related Docs
Endpoint usage and request field definitions.
Provider-specific payload templates.
Confirm final transaction outcome asynchronously.
# Collections - Inline
Source: https://docs.payfonte.com/en/guides/collections/inline
Embed Payfonte checkout directly on your website using the JavaScript SDK.
# Payfonte Inline
Inline checkout lets customers pay without leaving your page. You load the Payfonte SDK, initialize checkout with your transaction data, and open the payment iframe.
CDN SDK URL:
`https://cdn.payfonte.com/payfonte.min.js`
## Why Use Inline?
Customers stay on your site while completing payment.
Add one script and trigger checkout from your pay button.
Use callbacks for completion and close events in your app flow.
## Before You Start
Retrieve your `client-id` from `Settings -> Security -> API Keys and Webhooks` in [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com).
Use `sandbox` while testing and `production` only after go-live approval.
Create a unique `reference` for every payment attempt to avoid duplicates.
Never expose `client-secret` in frontend code. Inline checkout should only use
`client-id`.
## Quick Integration Example
```html Inline SDK theme={null}
Payfonte Inline
```
## Parameter Reference
| Field | Type | Required | Description |
| ------------- | -------- | ----------- | -------------------------------------------- |
| `environment` | string | Yes | `sandbox` or `production` |
| `reference` | string | Recommended | Unique transaction reference |
| `clientId` | string | Yes | Your Payfonte `client-id` |
| `amount` | integer | Yes | Amount in minor units (no decimals) |
| `currency` | string | Yes | ISO currency code (for example `NGN`) |
| `country` | string | Yes | ISO country code (for example `NG`) |
| `customer` | object | Yes | Customer details (name/email/phone) |
| `metadata` | object | No | Custom fields returned in callbacks/webhooks |
| `callback` | function | Yes | Runs after payment event payload is returned |
| `onClose` | function | No | Runs when checkout modal is closed |
## Amount Rule (Important)
Payfonte does not support decimal API amounts. Send integer minor-unit values only.
* `1000.00 NGN` -> `100000`
* `250.50 NGN` -> `25050`
See [Amount Specification](/en/guides/introductions/amount-specification) for full conversion guidance.
## Recommended Production Flow
Generate the transaction reference from your backend so you can enforce
uniqueness and map it to your internal order.
Treat frontend callback as a user experience signal. Final fulfillment
should depend on backend verification or webhook confirmation.
Always process [Webhooks](/en/guides/collections/webhook) to confirm final
transaction state (`success`/`failed`).
If callback/webhook repeats, ensure your order processing runs once per
reference.
## Troubleshooting
| Symptom | Likely Cause | Fix |
| ----------------------------------- | --------------------------------------- | ----------------------------------------------- |
| Checkout does not open | SDK script not loaded | Confirm script URL and browser console errors |
| Authentication/authorization issues | Invalid `clientId` or wrong environment | Use matching credentials for sandbox/production |
| Amount validation failure | Decimal amount used | Convert to integer minor units |
| Duplicate transaction error | Reused `reference` | Generate a new unique reference |
## Related Docs
Full SDK example and configuration reference.
Redirect-based alternative integration flow.
Validate final payment status on your backend.
# Overview
Source: https://docs.payfonte.com/en/guides/collections/overview
Accept mobile money API payments, bank transfers, and cards across African markets. MTN MoMo API, M-Pesa API, Airtel Money API, Wave Money integration.
Payfonte provides multiple methods to collect payments from your customers across Africa using our **payment orchestration API**. Accept all major **alternative payment methods (APM)** and **local payment methods in Africa** through a single integration.
***
## Integration Methods
**Embed on Your Page**
Display a payment form directly on your website without redirecting customers. Best for seamless checkout experiences.
**Redirect to Payfonte**
Redirect customers to a Payfonte-hosted payment page. Simplest integration with full payment method support.
**Server-to-Server**
Initiate charges directly via API for recurring payments or when you've already collected payment details.
**No-Code Option**
Generate shareable payment URLs from the dashboard. Perfect for invoices, social media, and email campaigns.
***
## Quick Comparison
| Method | Integration Effort | Customer Experience | Use Case |
| ----------------- | ------------------ | ----------------------- | ---------------------- |
| **Standard** | Low | Redirect to hosted page | Most merchants |
| **Inline** | Medium | Embedded on your site | Seamless UX |
| **Direct Charge** | High | No UI (server-side) | Recurring, saved cards |
| **Payment Links** | None | Click link to pay | Invoices, ad-hoc |
***
## Payment Flow Overview
```mermaid theme={null}
sequenceDiagram
participant Customer
participant Merchant
participant Payfonte
participant MNO/Bank
Customer->>Merchant: Initiates payment
Merchant->>Payfonte: Create checkout session
Payfonte-->>Merchant: Returns checkout URL
Merchant->>Customer: Redirect to checkout
Customer->>Payfonte: Selects payment method
Payfonte->>MNO/Bank: Process payment
MNO/Bank-->>Customer: Authorization prompt
Customer->>MNO/Bank: Confirms payment
MNO/Bank-->>Payfonte: Payment confirmed
Payfonte->>Merchant: Webhook notification
Payfonte->>Customer: Redirect to success URL
```
***
## Supported Alternative Payment Methods (APM)
| Region | Mobile Money API | Bank Transfer | Cards |
| --------------------- | ---------------------------------------------------- | ------------- | ----------- |
| **Nigeria** | **MTN MoMo API**, Airtel, Opay, PalmPay | ✅ Yes | Via partner |
| **Ghana** | **MTN MoMo API**, AirtelTigo, Telecel | Coming soon | Via partner |
| **Kenya** | **M-Pesa API** | ✅ Yes | Via partner |
| **Tanzania** | **M-Pesa API**, **Airtel Money API**, Halopesa, Tigo | Coming soon | - |
| **West Africa (CFA)** | Orange Money, MTN, **Wave Money integration**, Moov | - | - |
See [Supported Providers](/en/guides/introductions/supported-providers) for the complete list of **local payment methods in Africa**.
***
## Basic Collection Request
Here's a minimal example to create a checkout session:
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: YOUR_CLIENT_ID' \
--header 'client-secret: YOUR_CLIENT_SECRET' \
--header 'Content-Type: application/json' \
--data '{
"reference": "ORDER-001",
"amount": 5000,
"currency": "NGN",
"country": "NG",
"redirectURL": "https://yoursite.com/payment/complete",
"webhook": "https://yoursite.com/webhooks/payfonte",
"user": {
"email": "customer@example.com",
"phoneNumber": "08012345678"
}
}'
```
### Required Parameters
| Parameter | Type | Description |
| ------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| `reference` | string | Your unique order/transaction identifier |
| `amount` | integer | Payment amount in minor units (see [Amount Specification](/en/guides/introductions/amount-specification)) |
| `currency` | string | ISO currency code (NGN, KES, GHS, XOF, etc.) |
| `country` | string | ISO country code (NG, KE, GH, etc.) |
| `redirectURL` | string | URL to redirect customer after payment |
### Optional Parameters
| Parameter | Type | Description |
| ------------------ | ------ | ------------------------------------ |
| `webhook` | string | URL for payment notifications |
| `user.email` | string | Customer email address |
| `user.phoneNumber` | string | Customer phone number |
| `metadata` | object | Custom data to attach to transaction |
***
## Status values
Collection status values from API responses:
* `pending`
* `failed` - final
* `success` - final
## Handling Webhooks
We send webhook notifications for payment status changes. Always implement webhook handling for production:
```javascript theme={null}
app.post('/webhooks/payfonte', (req, res) => {
const event = req.body;
switch (event.event) {
case 'payment.completed':
// Payment successful - fulfill order
fulfillOrder(event.data.reference);
break;
case 'payment.failed':
// Payment failed - notify customer
notifyCustomer(event.data.reference);
break;
}
res.status(200).send('OK');
});
```
See [Webhooks](/en/guides/collections/webhook) for complete documentation.
***
## Best Practices
Generate unique `reference` values for each transaction. This prevents duplicate charges and simplifies reconciliation.
Your system should handle webhook retries gracefully. Check if an order is already fulfilled before processing.
After receiving a webhook, verify the transaction status via API before fulfilling orders.
Some payment methods (like USSD) take time to complete. Show appropriate waiting states to customers.
***
## Next Steps
Embed payments on your site
Redirect-based integration
Handle payment notifications
Full API documentation
# Collections - Payment Links
Source: https://docs.payfonte.com/en/guides/collections/payment-links
Create and manage shareable payment links for hosted customer payments.
Payment Links let you create hosted checkout URLs that customers can open from invoices, messages, social media, or email campaigns. A link can collect a fixed amount or allow the customer to enter an amount within configured limits.
When a customer completes payment through a payment link, Payfonte sends a payment webhook to your configured webhook endpoint. Use the webhook event as your source of truth before fulfilling the order or marking an invoice as paid.
See [Webhooks and Callbacks](/en/guides/collections/webhook) for the `payment.completed` payload, signature verification, retry handling, and webhook URL priority.
## Endpoints
| Method | Endpoint | Purpose |
| ------ | --------------------------------- | -------------------------------------- |
| `POST` | `/payments/v1/payment-links` | Create a payment link |
| `GET` | `/payments/v1/payment-links` | Fetch paginated payment links |
| `GET` | `/payments/v1/payment-links/{id}` | Fetch a payment link and its analytics |
## Integration Steps
Call `POST /payments/v1/payment-links` with `title`, `description`, currency, country, and amount settings. Send your client identifier in the `client-id` header.
Use the returned `shortURL` or `longURL` in invoices, emails, chats, social posts, or payment reminders.
After the customer pays, Payfonte sends a payment webhook to the configured endpoint. Verify the webhook signature and process the event idempotently.
Use `GET /payments/v1/payment-links/{id}` to retrieve the link, collected totals, channel breakdown, and provider availability.
## Create Payment Link
```bash theme={null}
curl --request POST \
--url https://sandbox-api.payfonte.com/payments/v1/payment-links \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'content-type: application/json' \
--data '{
"isAmountFixed": false,
"title": "decimal test",
"description": "demo",
"redirectURL": "",
"logo": "https://6thbridge-file-upload.s3.amazonaws.com/choosen-02.png",
"customFields": [],
"maximumAmount": 100000000,
"minimumAmount": 0,
"amountLimit": 100000000,
"currency": "XOF",
"country": "CI"
}'
```
Example response:
```json theme={null}
{
"statusCode": 201,
"data": {
"clientId": "6thbridge",
"locale": "en",
"logo": "https://6thbridge-file-upload.s3.amazonaws.com/choosen-02.png",
"currency": "XOF",
"country": "CI",
"title": "decimal test",
"description": "demo",
"isAmountFixed": false,
"longURL": "https://checkout-staging.6thbridge.com/link/6a7a2093b9e24880f73a80b0",
"shortURL": "https://s.6bd.co/payment-link/1PIDcH",
"minimumAmount": 0,
"maximumAmount": 100000000,
"amountLimit": 100000000,
"customFields": [],
"redirectURL": "",
"expiresAt": null,
"isActive": true,
"status": "active",
"parentClientId": "6thbridge",
"createdAt": "2026-08-10T19:03:47.222Z",
"updatedAt": "2026-08-10T19:03:47.222Z",
"id": "6a7a2093b9e24880f73a80b0"
}
}
```
## Request Fields
| Field | Type | Required | Description |
| --------------------------- | ------- | --------------------------------------- | --------------------------------------------------------------------------------------- |
| `title` | string | Yes | Human-readable payment link title |
| `description` | string | Yes | Human-readable payment link description |
| `currency` | string | Yes | Required 3-letter ISO currency code |
| `country` | string | Yes | Required 2-letter ISO country code used for active integration lookup |
| `isAmountFixed` | boolean | No | Set to `true` when the payer cannot change the amount |
| `amount` | number | Required when `isAmountFixed` is `true` | Fixed collection amount in minor units |
| `minimumAmount` | number | Used when `isAmountFixed` is `false` | Minimum payer-entered amount in minor units |
| `maximumAmount` | number | Used when `isAmountFixed` is `false` | Maximum payer-entered amount in minor units |
| `amountLimit` | number | No | Total collectible amount limit across successful payments for this link, in minor units |
| `customFields` | array | No | Extra payer fields to collect before creating checkout |
| `redirectURL` | string | No | URL to redirect the payer to after payment flow |
| `logo` | string | No | Logo URL or empty string. Defaults to the client or business logo |
| `locale` | string | No | Locale for payer-facing checkout. Defaults to the client or business locale |
| `isAnonymousPaymentEnabled` | boolean | No | Whether anonymous payments are allowed |
| `expiresAt` | date | No | Date on which the link expires |
## Amount Modes
Use `isAmountFixed: true` when the customer must pay one exact amount. Send `amount` with a value greater than zero.
```json theme={null}
{
"isAmountFixed": true,
"amount": 50000,
"currency": "NGN",
"country": "NG",
"title": "Invoice 1001",
"description": "Payment for invoice 1001"
}
```
Use `isAmountFixed: false` when the customer can enter the payment amount. Send `minimumAmount` and `maximumAmount` to define the allowed range.
```json theme={null}
{
"isAmountFixed": false,
"minimumAmount": 10000,
"maximumAmount": 200000,
"amountLimit": 1000000,
"currency": "NGN",
"country": "NG",
"title": "Donation",
"description": "Choose how much to pay"
}
```
## Custom Fields
Use `customFields` when you need extra payer information before checkout is created. Choice fields require `options`.
Supported `customFields.type` values:
| Type | Use case |
| ---------------- | ------------------------------------- |
| `text` | Short free-text input |
| `paragraph-text` | Longer free-text input |
| `dropdown` | Single choice from predefined options |
| `number` | Numeric input |
| `date` | Date input |
| `file-upload` | File attachment |
| `checkbox` | Boolean confirmation |
```json theme={null}
{
"customFields": [
{
"label": "Invoice number",
"name": "invoiceNumber",
"type": "text",
"required": true
},
{
"label": "Package",
"name": "package",
"type": "dropdown",
"required": true,
"options": ["Basic", "Premium"]
}
]
}
```
## Fetch Payment Links
```bash theme={null}
curl --request GET \
--url 'https://sandbox-api.payfonte.com/payments/v1/payment-links?page=1&limit=2' \
--header 'client-id: ' \
--header 'client-secret: '
```
## Fetch Payment Link By ID
```bash theme={null}
curl --request GET \
--url https://sandbox-api.payfonte.com/payments/v1/payment-links/6a7204a536c2106e38fe8e01 \
--header 'client-id: ' \
--header 'client-secret: '
```
The response includes the payment link fields and an `analytics` object with collected amount, transaction count, channel breakdown, revenue history, available providers, and available channels.
## Webhook Completion
Payment links use the same collection webhook flow documented in [Webhooks and Callbacks](/en/guides/collections/webhook). When a customer successfully completes a payment link checkout, Payfonte sends a payment webhook such as `payment.completed`.
Validate `x-webhook-signature` with your `client-secret` before processing the event.
Track processed `reference` and `status` values so retries do not trigger duplicate fulfillment.
Mark invoices, orders, or balances as paid only after receiving and validating a final webhook status such as `success`.
## Important Rules
Amount values are sent in minor units. See [Amount Specification](/en/guides/introductions/amount-specification).
Do not rely only on customer redirect behavior to confirm payment. Always process the payment webhook before fulfilling value.
## Related Docs
View payment link endpoint definitions and request schemas.
Receive and verify payment completion events.
Understand how to send amount values in minor units.
# Collection - Standard Checkout
Source: https://docs.payfonte.com/en/guides/collections/standard
Redirect customers to Payfonte hosted checkout using a server-side API request.
Standard checkout is a redirect flow:
1. Your backend creates a checkout session.
2. Payfonte returns a checkout URL.
3. You redirect the customer to that URL.
4. Customer completes payment and Payfonte notifies your system via webhook.
## Why Use Standard Checkout?
Minimal frontend complexity. Your backend creates a checkout and redirects users.
Payfonte handles payment method UI and provider-specific interactions.
Use webhook events and transaction verification for final payment outcomes.
## Integration Steps
Prepare required fields like `amount`, `currency`, `country`, and customer information.
Send a request to `POST /payments/v1/checkouts` with your `client-id` and `client-secret`.
Redirect users to `data.shortURL` (or `data.url`) from the response.
Process webhook notifications and/or verify transaction status before order fulfillment.
## Create Checkout Request
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "ORDER-1001",
"amount": 50000,
"currency": "NGN",
"country": "NG",
"redirectURL": "https://yourapp.com/payment/complete",
"webhook": "https://yourapp.com/webhooks/payfonte",
"user": {
"email": "customer@example.com",
"phoneNumber": "2348012345678",
"name": "John Doe"
}
}'
```
Sample response:
```json theme={null}
{
"data": {
"url": "https://checkout-staging.payfonte.com/payfusion/66579afe04916ddcfcf73e7b",
"shortURL": "https://l.6bd.co/XXXXX",
"reference": "ORDER-1001",
"amount": 50000
}
}
```
## Parameter Reference
| Field | Type | Required | Description |
| ------------- | ------- | ----------- | ---------------------------------------------- |
| `reference` | string | Recommended | Unique transaction identifier from your system |
| `amount` | integer | Yes | Amount in minor units (no decimals) |
| `currency` | string | Yes | ISO currency code (for example `NGN`) |
| `country` | string | Yes | ISO country code (for example `NG`) |
| `user` | object | Yes | Customer object (email/phone/name fields) |
| `redirectURL` | string | No | Customer return URL after checkout |
| `webhook` | string | No | Per-transaction webhook override URL |
| `metadata` | object | No | Custom fields for your internal tracking |
## Amount Rule (Important)
Payfonte does not support decimal API amounts. Send integer minor-unit values only.
* `500.00 NGN` -> `50000`
* `1250.75 NGN` -> `125075`
See [Amount Specification](/en/guides/introductions/amount-specification) for full conversion rules.
## After Redirect and Payment
After checkout, customer is redirected to your `redirectURL` with transaction context such as `status` and `reference`.
If webhooks are configured, Payfonte sends asynchronous status updates to your webhook endpoint.
For critical flows, verify transaction status from your backend before shipping goods or crediting wallets.
If payment fails, allow user retry and keep your order state pending until final success is confirmed.
## Production Best Practices
| Practice | Why It Matters |
| ------------------------------- | ------------------------------------------------------- |
| Generate references server-side | Prevent duplicate references and improve reconciliation |
| Process webhook idempotently | Avoid duplicate order fulfillment on retries |
| Validate redirect parameters | Protect against malformed/forged client-side values |
| Use backend verification | Ensure final status before business-critical actions |
## Related Docs
Embedded checkout alternative for on-page payment.
Set up and validate payment event callbacks.
Endpoint and schema details for checkout operations.
# Webhooks and Callbacks
Source: https://docs.payfonte.com/en/guides/collections/webhook
Receive and verify real-time collection payment updates from Payfonte.
Payfonte sends webhook events to your configured endpoint when payment state changes.
Use webhooks as your primary source of truth for asynchronous payment outcomes.
## Webhook Source IPs
If you restrict inbound traffic by IP address, allowlist the following Payfonte webhook source IPs for each environment.
| Environment | Source IPs |
| ----------- | ------------------------------------------------ |
| Production | `49.13.133.127`, `49.13.229.61`, `194.32.79.135` |
| Sandbox | `49.12.224.228`, `49.13.224.113` |
## Why Webhooks Matter
Get payment updates without polling every transaction.
Confirm final status (`success` or `failed`) before fulfilling orders.
Handle retries with idempotent processing to avoid duplicate fulfillment.
## Webhook Payload Fields
| Field | Description |
| ------------------------ | ------------------------------------------------------ |
| `event` | Event type (for example `payment.completed`) |
| `clientId` | Your Payfonte client identifier |
| `data.status` | Transaction status (`success`, `failed`, or `pending`) |
| `data.reference` | Payfonte transaction reference |
| `data.externalReference` | Merchant-provided reference (if supplied) |
| `data.amount` | Transaction amount in minor units |
| `data.charge` | Applied transaction charge |
| `data.provider` | Provider slug/name used for processing |
| `data.channel` | Payment channel (for example `card`, `mobile-money`) |
| `data.user` | Customer metadata (name/email/phone when available) |
Sample payload:
```json payment.completed theme={null}
{
"clientId": "solara_textiles",
"data": {
"amount": 74250,
"channel": "mobile-money",
"charge": 1856,
"clientId": "solara_textiles",
"completedAt": "2026-05-08T09:24:51.127Z",
"country": "SN",
"currency": "XOF",
"externalReference": "ord_8473926150",
"id": "7f24c91a6b8e45d2f1309c7a",
"locale": "en",
"metadata": {},
"paidAt": 1778232291,
"paymentReference": "PF20260508092451QZRM4",
"platformReference": "7f24c91a6b8e45d2f1309c7a",
"provider": "wave-senegal",
"reference": "PF20260508092451QZRM4",
"status": "success",
"statusDescription": "succeeded",
"user": {
"phoneNumber": "221771234589"
}
},
"deliveryId": "7f24c923bb1d0e4a9c8156fd",
"event": "payment.completed",
"reference": "PF20260508092451QZRM4",
"webhook": "https://merchant.example.com/webhooks/payfonte?client_id=solara_textiles"
}
```
## Signature Verification (Required)
Every webhook includes:
* Header: `x-webhook-signature`
* Value: `sha512` HMAC digest of raw request body, signed with your `client-secret`
Use your `client-secret` from `Settings -> Security -> API Keys and Webhooks`.
```javascript theme={null}
const crypto = require("crypto");
app.post("/payfonte/webhook", express.json({ type: "*/*" }), (req, res) => {
const secret = process.env.PAYFONTE_CLIENT_SECRET;
const payload = JSON.stringify(req.body);
const expected = crypto
.createHmac("sha512", secret)
.update(payload)
.digest("hex");
const received = req.headers["x-webhook-signature"];
if (expected !== received) {
return res.status(401).send("Invalid signature");
}
// Acknowledge quickly, then process asynchronously.
res.status(200).send("OK");
processWebhook(req.body);
});
```
If signature validation fails, do not process the event.
## Idempotent Processing Pattern
Return HTTP `200` quickly to prevent unnecessary retries.
Use `reference` + `status` (or a delivery identifier if available) to detect
already-processed events.
For critical flows, verify payment status from your backend before final
fulfillment.
Ensure business actions (for example order fulfillment) run once per final
success.
## Webhook URL Priority
Payfonte uses webhook URLs in this order:
1. Webhook URL passed in the checkout/direct-charge request (`webhook`)
2. Webhook URL configured on the provider integration
3. Webhook URL configured in dashboard settings
## Common Issues
| Issue | Likely Cause | Fix |
| ---------------------------- | ---------------------------------- | ------------------------------------------------------------ |
| Duplicate webhook processing | No idempotency guard | Track processed `reference` + `status` and skip repeats |
| Signature mismatch | Wrong secret or payload mutation | Use correct `client-secret` and hash the exact received body |
| Missed updates | Endpoint timeout/non-200 responses | Return `200` quickly and move heavy work to async workers |
| Wrong environment events | Mixed sandbox/production setup | Use matching endpoint and credentials per environment |
## Related Docs
Redirect flow with webhook completion.
Direct charge flow and action handling.
Credential and header requirements.
# Disbursement Authorization Mode
Source: https://docs.payfonte.com/en/guides/disbursements/authorization-mode
Configure secure authorization for disbursement requests using PIN mode or Authorization URL mode.
# Disbursement Authorization Mode
Payfonte supports two authorization modes for disbursement requests:
* PIN Authorization
* Authorization URL
## Mode Comparison
| Mode | How it works | Recommended for |
| ----------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| PIN Authorization | You send `pin` in each disbursement request | Teams with strict backend-controlled disbursement flows |
| Authorization URL | Payfonte calls your approval endpoint per request; disbursement continues only on HTTP `200` | Platforms that require policy/risk checks before each disbursement |
## 1) PIN Authorization
PIN mode requires a disbursement PIN on disbursement requests.
### Setup
Open any Disbursements page in dashboard and complete PIN setup when prompted.
Keep PIN in backend secret storage only. Never expose in frontend/mobile clients.
Include `pin` field in `POST /billing/v1/disbursements`.
PIN request example:
```json theme={null}
{
"transferRecipientId": "6659692f019f6a143f7f90db",
"amount": 100000,
"reference": "disbursement-1001",
"narration": "Vendor settlement",
"pin": "1234"
}
```
## 2) Authorization URL
Authorization URL mode lets your system approve or reject each disbursement attempt dynamically.
### Setup
Set your endpoint under `Disbursements -> Settings` in dashboard.
Validate incoming request authenticity (hash/signature verification) before responding.
Return HTTP `200` to approve; non-`200` to block the disbursement.
Authorization URL mode is strict: if your endpoint is unavailable or returns non-`200`, the disbursement is not processed.
### Authorization Request Payload
When Authorization URL mode is enabled, Payfonte sends a JSON payload like this to your configured authorization URL:
```json theme={null}
{
"clientId": "client_123456789",
"type": "disbursement",
"externalReference": "EXT-DISB-000001",
"reference": "DISB-000001",
"provider": "paystack",
"channel": "bank-transfer",
"finalAmount": 500000,
"amount": 500000,
"transferRecipientLabel": "Paystack | Zenith Bank | Ada Lovelace | 0123456789",
"transferRecipient": {
"accountNumber": "0123456789",
"bankCode": "057",
"bankName": "Zenith Bank",
"accountName": "Ada Lovelace"
},
"recipient": {
"accountNumber": "0123456789",
"bankCode": "057",
"bankName": "Zenith Bank",
"accountName": "Ada Lovelace"
},
"transferRecipientId": "trf_recipient_123456789",
"charge": 15000,
"chargesApplied": [],
"fees": {},
"status": "queued",
"country": "NG",
"currency": "NGN",
"narration": "Vendor payout for invoice INV-2026-0001",
"webhookURL": "https://example.com/webhooks/disbursements"
}
```
## Recommended Validation Checks (Authorization URL)
When Payfonte calls your authorization URL, validate:
* Request authenticity (signature/hash verification)
* Amount and currency match expected business rules
* Recipient is eligible for disbursement
* Sender/account has enough balance (if you enforce internal wallet rules)
* Daily limits, AML/risk policies, and velocity thresholds
## Security Checklist
Never expose disbursement PIN or authorization secrets in browser/mobile code.
Authorization URL must be publicly reachable over HTTPS.
If signature/hash checks fail, reject the authorization request.
Log both approved and rejected decisions with reasons for compliance and troubleshooting.
## Related Docs
End-to-end disbursement flow and endpoint usage.
Handle asynchronous disbursement status updates.
Copy-ready request and response payloads.
# Disbursement Example Payloads
Source: https://docs.payfonte.com/en/guides/disbursements/examples
Copy-ready payload examples for recipient validation, disbursement requests, and disbursement verification.
# Disbursement Example Payloads
This page provides practical payloads for each major disbursement step:
1. Validate recipient
2. Request disbursement
3. Verify disbursement
## 1) Validate Recipient
Use the matching account object for the provider channel you are validating.
### Mobile Money
Endpoint: `POST /billing/v1/transfer-recipients/validate`
```json theme={null}
{
"provider": "mtn-momo-ivory-coast",
"account": {
"phoneNumber": "225XXXXXXXXXX"
}
}
```
Sample response:
```json theme={null}
{
"statusCode": 200,
"data": {
"provider": "mtn-momo-ivory-coast",
"providerLabel": "MTN MoMo",
"source": "disbursement",
"channel": "mobile-money",
"currency": "XOF",
"country": "CI",
"accountLabel": "MTN MoMo | 225XXXXXXXXXX",
"account": {
"network": "MTN",
"phoneNumber": "225XXXXXXXXXX",
"accountName": "John Doe"
},
"status": "active",
"id": "675a4528d14b406a3d31e4a8"
}
}
```
### Bank Transfer
Fetch the bank list before validating a bank transfer recipient so you can send a valid `bankCode`.
Endpoint: `GET /billing/v1/transfer-recipients/{provider}/properties`
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/billing/v1/transfer-recipients/bank-transfer-nigeria/properties' \
--header 'client-id: ' \
--header 'client-secret: '
```
Sample response:
```json theme={null}
{
"statusCode": 200,
"data": {
"banks": [
{
"bankName": "Access Bank",
"bankCode": "044"
}
]
}
}
```
Use the selected `bankCode` when validating the recipient.
Endpoint: `POST /billing/v1/transfer-recipients/validate`
```json theme={null}
{
"provider": "bank-transfer-nigeria",
"account": {
"accountNumber": "0123456789",
"bankCode": "044"
}
}
```
Sample response:
```json theme={null}
{
"statusCode": 200,
"data": {
"provider": "bank-transfer-nigeria",
"providerLabel": "Bank Transfer",
"source": "disbursement",
"channel": "bank-transfer",
"currency": "NGN",
"country": "NG",
"accountLabel": "Access Bank | AAA BBB XXX | 0123456789",
"account": {
"name": "AAA BBB XXX",
"accountName": "AAA BBB XXX",
"accountNumber": "0123456789",
"bankCode": "044",
"bankName": "Access Bank"
},
"status": "pending",
"id": "6834655cdc1370231451f2a5"
}
}
```
### Bank Transfer (Angola)
Endpoint: `POST /billing/v1/transfer-recipients/validate`
```json theme={null}
{
"provider": "bank-transfer-angola",
"account": {
"accountName": "John Doe",
"accountNumber": "0123456789"
}
}
```
Sample response:
```json theme={null}
{
"statusCode": 200,
"data": {
"clientId": "6thbridge",
"parentClientId": "payfusion",
"ownerType": "client",
"ownerId": "6thbridge",
"provider": "bank-transfer-angola",
"providerLabel": "Bank Transfer",
"providerLogo": "https://app-tst.appypay.co.ao/images/payment-methods/ref.png",
"source": "disbursement",
"channel": "bank-transfer",
"currency": "AOA",
"country": "AO",
"tags": [],
"accountLabel": "Bank Transfer | Miss Billie Friesen | 2215381176",
"account": {
"accountNumber": "2215381176",
"accountName": "Miss Billie Friesen"
},
"status": "pending",
"createdAt": "2026-04-20T12:40:56.084Z",
"updatedAt": "2026-04-20T12:40:56.084Z",
"id": "69e61ed8c5938efd8ef63e1b"
}
}
```
## 2) Request Disbursement
Endpoint: `POST /billing/v1/disbursements`
```json theme={null}
{
"transferRecipientId": "675a4528d14b406a3d31e4a8",
"amount": 3000,
"reference": "disbursement-1001",
"narration": "Vendor disbursement",
"pin": "1111",
"webhookURL": "https://yourdomain.com/webhook",
}
```
Sample response:
```json theme={null}
{
"statusCode": 201,
"data": {
"reference": "D20241216141720XXXXX",
"amount": 3000,
"amountPayable": 3000,
"charge": 15,
"provider": "mtn-momo-ivory-coast",
"currency": "XOF",
"country": "CI",
"status": "processing"
}
}
```
## 3) Verify Disbursement
Endpoint: `GET /billing/v1/disbursements/verify/{reference}`
Sample response:
```json theme={null}
{
"data": {
"clientId": "payfusion",
"status": "success",
"statusDescription": "success",
"reference": "D20241223060657MOHAA",
"providersReference": "pt-D20241223060657MOHAA",
"externalReference": "D20241223060657MOHAA",
"currency": "XOF",
"country": "CI",
"transferRecipientId": "6768fdf84764676cde0b630e",
"transferRecipientLabel": "Wave | +2257038102474",
"charge": 0,
"amount": 3000,
"finalAmount": 3000,
"provider": "wave-ivory-coast",
"channel": "mobile-money",
"integrationId": "6762bcccdd35fc1c7cae5bd6",
"id": "6768fe014764676cde0b6313"
},
"statusCode": 200
}
```
## Validation Checklist
Send integer minor-unit values only. Decimals are not supported.
Use a unique disbursement reference to avoid duplicate transaction errors.
Always validate recipient before requesting disbursement.
Ensure request matches your configured authorization mode (PIN or Authorization URL).
## Related Docs
Full disbursement flow walkthrough.
Configure and secure disbursement authorization.
Process status callbacks safely.
# Overview
Source: https://docs.payfonte.com/en/guides/disbursements/overview
End-to-end Disbursement flow for validating recipients, requesting disbursements, and verifying final transaction status.
Use Payfonte disbursements to send Disbursements to validated recipients across supported providers and markets.
## Flow Summary
Confirm recipient account details before Disbursement.
Initiate Disbursement with amount, recipient ID, and authorization mode.
Confirm outcome using verification endpoint and/or webhook.
## Disbursement Flow Overview
```mermaid theme={null}
sequenceDiagram
participant Merchant as Merchant Backend
participant Payfonte
participant Provider as MNO/Bank Provider
participant Recipient
Merchant->>Payfonte: Validate recipient details
Payfonte->>Provider: Validate account/wallet
Provider-->>Payfonte: Validation result
Payfonte-->>Merchant: transferRecipientId
Merchant->>Payfonte: Request disbursement
Payfonte->>Provider: Initiate Disbursement
Provider-->>Recipient: Credit recipient account/wallet
Provider-->>Payfonte: Status update
Payfonte-->>Merchant: Webhook notification
Merchant->>Payfonte: Verify by reference
Payfonte-->>Merchant: Final status (success/failed)
```
## Endpoints
| Method | Endpoint | Purpose |
| ------ | ------------------------------------------------------- | --------------------------------------------- |
| `GET` | `/billing/v1/transfer-recipients/{provider}/properties` | Fetch provider-specific properties (optional) |
| `POST` | `/billing/v1/transfer-recipients/validate` | Validate recipient details |
| `POST` | `/billing/v1/disbursements` | Request disbursement |
| `GET` | `/billing/v1/disbursements/verify/{reference}` | Verify disbursement status |
## Prerequisites
* Valid `client-id` and `client-secret`
* Sufficient Disbursement wallet balance
* Disbursement authorization setup (`pin` or authorization URL flow)
* Valid provider slug from [Supported Providers](/en/guides/introductions/supported-providers)
## Step 1: Validate Transfer Recipient
### 1.1 Fetch provider properties (optional)
Some providers require extra details (for example bank list/network options) before validation.
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/billing/v1/transfer-recipients/{provider}/properties' \
--header 'client-id: ' \
--header 'client-secret: '
```
### 1.2 Validate recipient
Bank transfer example:
```json theme={null}
{
"provider": "bank-transfer-nigeria",
"account": {
"accountNumber": "0123456789",
"bankCode": "044"
}
}
```
Mobile money example:
```json theme={null}
{
"provider": "wave-ivory-coast",
"account": {
"phoneNumber": "2250538102474"
}
}
```
Sample response:
```json theme={null}
{
"data": {
"id": "recipient-id",
"currency": "NGN",
"country": "NG",
"provider": "bank-transfer-nigeria",
"accountLabel": "Bank Transfer | Zenith Bank | Dummy User | 0123456789",
"account": {
"accountNumber": "0123456789",
"bankCode": "044"
}
}
}
```
Save `data.id` as your `transferRecipientId`.
## Step 2: Request Disbursement
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/billing/v1/disbursements' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"transferRecipientId": "6659692f019f6a143f7f90db",
"amount": 100000,
"reference": "Disbursement-1001",
"narration": "Vendor settlement",
"pin": "1234",
"webhookURL": "https://yourapp.com/webhooks/payfonte"
}'
```
Sample response:
```json theme={null}
{
"data": {
"reference": "Disbursement-1001",
"amount": 100000,
"amountPayable": 100000,
"provider": "bank-transfer-nigeria",
"currency": "NGN",
"country": "NG",
"status": "processing"
}
}
```
### Request fields
| Field | Type | Required | Description |
| --------------------- | ------- | ----------- | ----------------------------------------------- |
| `transferRecipientId` | string | Yes | ID from recipient validation step |
| `amount` | integer | Yes | Amount in minor units (no decimals) |
| `reference` | string | Recommended | Unique Disbursement reference |
| `narration` | string | No | Disbursement description |
| `pin` | string | Conditional | Required when PIN authorization mode is enabled |
| `webhookURL` | string | No | Override webhook URL for this Disbursement |
### Status values
Disbursement status values from API responses:
* `processing`
* `success`
* `failed`
## Step 3: Verify Disbursement
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/billing/v1/disbursements/verify/Disbursement-1001' \
--header 'client-id: ' \
--header 'client-secret: '
```
Sample response:
```json theme={null}
{
"data": {
"status": "success",
"reference": "Disbursement-1001",
"externalReference": "Disbursement-1001",
"amount": 100000,
"currency": "NGN"
}
}
```
## Amount Rule (Important)
Payfonte does not support decimal API amounts. Send integer minor-unit values only.
* `1000.00 NGN` -> `100000`
* `250.75 NGN` -> `25075`
See [Amount Specification](/en/guides/introductions/amount-specification).
## Best Practices
Validation reduces failed Disbursements caused by invalid account details.
Reuse validated recipients to avoid repeated validation requests.
Unique references prevent duplicate Disbursement issues and simplify reconciliation.
Process webhook events and verify final status for critical business actions.
Keep disbursement PIN and authorization URLs strictly server-side.
## Related Docs
Configure PIN or authorization URL mode.
Request and response payload examples.
Handle Disbursement status updates asynchronously.
# Disbursement Webhooks and Callbacks
Source: https://docs.payfonte.com/en/guides/disbursements/webhook
Receive, verify, and process real-time disbursement status updates.
Payfonte sends webhook events when disbursement status changes (for example `processing`, `success`, `failed`).
Use webhooks as your primary asynchronous disbursement update channel.
## Webhook Source IPs
If you restrict inbound traffic by IP address, allowlist the following Payfonte webhook source IPs for each environment.
| Environment | Source IPs |
| ----------- | ------------------------------------------------ |
| Production | `49.13.133.127`, `49.13.229.61`, `194.32.79.135` |
| Sandbox | `49.12.224.228`, `49.13.224.113` |
## Payload Fields
| Field | Description |
| ----------------------------- | ------------------------------------------------------- |
| `event` | Event type (for example `disbursement.status`) |
| `clientId` | Your Payfonte client ID |
| `data.status` | disbursement status (`processing`, `success`, `failed`) |
| `data.statusDescription` | Provider/platform status detail |
| `data.reference` | Payfonte disbursement reference |
| `data.externalReference` | Merchant-provided reference |
| `data.providersReference` | Provider reference |
| `data.amount` | disbursement amount in minor units |
| `data.charge` | Applied disbursement charge |
| `data.provider` | Provider slug used |
| `data.transferRecipientId` | Recipient identifier |
| `data.transferRecipientLabel` | Human-readable recipient label |
| `deliveryId` | Webhook delivery identifier |
Sample payload:
```json disbursement.status theme={null}
{
"event": "disbursement.status",
"clientId": "payfusion",
"data": {
"clientId": "payfusion",
"type": "disbursement",
"status": "success",
"statusDescription": "Disbursement was successful",
"reference": "L20250614142024AAAAA",
"providersReference": "reference-from-mno",
"externalReference": "merchant-reference",
"currency": "XOF",
"country": "BJ",
"transferRecipientId": "684d561743dac722bcd43e9f",
"transferRecipientLabel": "MTN MoMo | 2290123456789",
"charge": 180,
"amount": 10000,
"provider": "mtn-momo-benin",
"providerLabel": "MTN MoMo",
"providerLogo": "https://payfonte.s3.amazonaws.com/mtn-momo.png",
"channel": "mobile-money",
"timestamp": "2025-06-14T14:20:25.023Z",
"narration": "disbursement narration here",
"completedAt": 1749910827
},
"deliveryId": "684d852b27e08e60f4d09103"
}
```
## Signature Verification
Validate webhook authenticity before processing.
* Header: `x-webhook-signature`
* Algorithm: `sha512` HMAC of request body using your `client-secret`
```javascript theme={null}
const crypto = require("crypto");
app.post("/payfonte/disbursement-webhook", express.json({ type: "*/*" }), (req, res) => {
const secret = process.env.PAYFONTE_CLIENT_SECRET;
const payload = JSON.stringify(req.body);
const expected = crypto.createHmac("sha512", secret).update(payload).digest("hex");
const received = req.headers["x-webhook-signature"];
if (expected !== received) {
return res.status(401).send("Invalid signature");
}
res.status(200).send("OK");
processDisbursementWebhook(req.body);
});
```
## Safe Processing Pattern
Return HTTP `200` immediately after basic validation.
Deduplicate by `reference` + `status` (or `deliveryId`) before applying business actions.
Mark disbursement as final only for terminal statuses and save `statusDescription`.
Optionally confirm final state using `GET /billing/v1/disbursements/verify/{reference}`.
## Common Issues
| Issue | Likely Cause | Fix |
| ------------------------------ | ------------------------------- | ------------------------------------------------------- |
| Duplicate webhook processing | No idempotency handling | Store processed reference/status and skip repeats |
| Signature mismatch | Wrong secret or mutated payload | Use correct `client-secret` and hash exact request body |
| Missed status updates | Timeout/non-200 responses | Return 200 quickly; move heavy logic to async worker |
| Conflicting disbursement state | Out-of-order processing | Always compare current state before applying updates |
## Related Docs
End-to-end disbursement flow and endpoints.
Request/response payload samples.
PIN vs Authorization URL configuration.
# Amount Specification
Source: https://docs.payfonte.com/en/guides/introductions/amount-specification
How to format amounts for Payfonte APIs using the smallest currency denomination.
Payfonte expects `amount` values in the **smallest denomination** of the currency (minor unit).
Use this rule:
`amount_to_send = major_amount * 100`
Example: `100.50 NGN` becomes `10050`.
Do not send decimal values in API requests. Always send integer amounts.
## Why This Format?
Prevents floating-point rounding issues in financial calculations.
Same amount format across collections, disbursements, and wallets.
Matches how payment providers process transaction values internally.
## Quick Conversion Table
| Currency | Major Unit | Minor Unit | Example |
| -------- | ---------- | ---------- | --------------------- |
| NGN | Naira | Kobo | `100.00 NGN -> 10000` |
| GHS | Cedi | Pesewa | `50.00 GHS -> 5000` |
| KES | Shilling | Cent | `100.00 KES -> 10000` |
| XOF | CFA Franc | Minor unit | `10.00 XOF -> 1000` |
| USD | Dollar | Cent | `25.99 USD -> 2599` |
## API Examples
The examples below show the same rule in real requests:
* `1250.75 NGN` is sent as `125075` (`amount` in kobo)
* `10000.00 NGN` is sent as `1000000` (`amount` in kobo)
```json Collections theme={null}
{
"currency": "NGN",
"amount": 125075,
"reference": "ORDER-1001"
}
```
```json Disbursements theme={null}
{
"transferRecipientId": "6659692f019f6a143f7f90db",
"amount": 1000000,
"reference": "disbursement-1001"
}
```
## Common Mistakes
* Incorrect: `"amount": 1250.75`
* Correct: `"amount": 125075`
Do not send some requests in major units and others in minor units. Standardize conversion in one shared utility.
Conversion logic should run on your backend so it stays controlled and consistent.
## Recommended Implementation Pattern
Keep your display and business logic readable (for example `1250.75`).
Convert to minor unit integer (`125075`) at your service boundary.
Log `displayAmount` and `apiAmount` so reconciliation is easier.
## Related Docs
Add required auth headers to your requests.
Understand wallet balances and wallet states.
Explore request/response schemas.
# Authorization
Source: https://docs.payfonte.com/en/guides/introductions/authorization
Authenticate Payfonte API requests using client-id and client-secret headers.
Every Payfonte API request is authenticated using two headers:
* `client-id`
* `client-secret`
Never expose `client-secret` in frontend apps, mobile apps, browser storage,
or public repositories.
## Authentication Model
Public identifier for your account and environment.
Secret key used to authorize requests. Store only on trusted backend
systems.
Pass both credentials in request headers on every API call.
Sandbox and Production use different credentials. Do not mix them.
## Where To Get Your Keys
Use [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com) for testing or [app.payfonte.com](https://app.payfonte.com) for live operations.
Navigate to `Settings -> Security -> API Keys and Webhooks`.
Save your `client-id` and `client-secret` into server environment variables.
## Request Example
```bash cURL theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "test-001",
"amount": 1000,
"currency": "NGN",
"country": "NG",
"user": {
"phoneNumber": "08012345678"
}
}'
```
```javascript Node.js (fetch) theme={null}
await fetch("https://sandbox-api.payfonte.com/payments/v1/checkouts", {
method: "POST",
headers: {
"Content-Type": "application/json",
"client-id": process.env.PAYFONTE_SANDBOX_CLIENT_ID,
"client-secret": process.env.PAYFONTE_SANDBOX_CLIENT_SECRET,
},
body: JSON.stringify({
reference: "test-001",
amount: 1000,
currency: "NGN",
country: "NG",
user: { phoneNumber: "08012345678" },
}),
});
```
## Common Mistakes
Sandbox and production are separate environments. Use the matching base URL
and matching credentials together.
Frontend code is public to end users. Keep all authenticated Payfonte API
calls on your backend.
Requests without either `client-id` or `client-secret` will fail
authentication.
Always load credentials from environment variables or a secure secret
manager.
## Security Checklist
* Keep `client-secret` on backend only.
* Use HTTPS for API and webhook endpoints.
* Rotate credentials if exposure is suspected.
* Restrict internal access to production secrets.
## Related Docs
Sandbox and production URL/key setup.
Make your first successful API call.
Full endpoint and schema details.
# Endpoint Specification
Source: https://docs.payfonte.com/en/guides/introductions/endpoint-specification
Request and response conventions for Payfonte APIs, including authentication, pagination, filtering, and error envelopes.
This page defines the common request/response patterns used across Payfonte APIs.
## Request Conventions
Use HTTPS endpoints and JSON payloads for API requests.
Send `client-id` and `client-secret` headers on every request.
Send integer minor-unit amounts only. Decimals are not supported.
## Required Headers
```bash theme={null}
client-id:
client-secret:
Content-Type: application/json
```
## Base URLs
| Environment | Base URL |
| ----------- | ---------------------------------- |
| Sandbox | `https://sandbox-api.payfonte.com` |
| Production | `https://api.payfonte.com` |
## Response Structure
### Success Responses (2xx)
Most successful responses follow this shape:
```json theme={null}
{
"data": {}
}
```
Some list endpoints also return pagination metadata:
```json theme={null}
{
"statusCode": 200,
"total": 1253,
"page": 1,
"pages": 314,
"limit": 4,
"data": []
}
```
### Error Responses (4xx/5xx)
```json theme={null}
{
"error": "Validation failed",
"errorCode": "ValidationError"
}
```
Always branch your handling logic using both HTTP status code and `errorCode`.
## Pagination and Filtering
List endpoints such as `GET /payments/v1/checkouts` and `GET /billing/v1/disbursements` support:
* `page` (default: `1`)
* `limit` (default: `4`, max: `100`)
* `dateFrom` (optional, `YYYY-MM-DD`)
* `dateTo` (optional, `YYYY-MM-DD`)
Example:
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts?page=1&limit=20&dateFrom=2025-01-01&dateTo=2025-01-31' \
--header 'client-id: ' \
--header 'client-secret: '
```
## Webhook Override Fields
Certain endpoints allow request-level webhook overrides:
* Collections endpoints use `webhook`
* Disbursement request uses `webhookURL`
Use these only when you need an endpoint-specific callback different from your dashboard default.
## Amount Formatting Rule
Payfonte does not support decimal amounts in API requests.
* Incorrect: `"amount": 1250.75`
* Correct: `"amount": 125075`
See [Amount Specification](/en/guides/introductions/amount-specification) for conversion rules.
## Related Docs
Required auth headers and secure credential handling.
Troubleshoot common API failures.
Endpoint-level schema and operation details.
# Environments
Source: https://docs.payfonte.com/en/guides/introductions/environments
Configure sandbox and production environments, API base URLs, and authentication with client-id and client-secret.
# Environments
Payfonte provides two environments for integration:
| Environment | Use Case | API Base URL | Dashboard |
| ----------- | ------------------ | ---------------------------------- | -------------------------------------------------------------------- |
| Sandbox | Development and QA | `https://sandbox-api.payfonte.com` | [https://sandbox-app.payfonte.com](https://sandbox-app.payfonte.com) |
| Production | Live transactions | `https://api.payfonte.com` | [https://app.payfonte.com](https://app.payfonte.com) |
Do not use live provider credentials in sandbox. Keep sandbox and production
credentials separate.
## API Authentication
All API calls require these headers:
* `client-id`
* `client-secret`
You can find both in:
`Dashboard -> Settings -> Security -> API Keys and Webhooks`
## Sandbox Example
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "test-001",
"amount": 1000,
"currency": "NGN",
"country": "NG",
"user": {
"phoneNumber": "08012345678"
}
}'
```
## Production Go-Live Checklist
Validate successful, failed, and pending flows, including webhooks.
Submit your business details using the [KYB onboarding form](https://form.jotform.com/240038360690048).
Replace sandbox `client-id`/`client-secret` with production keys and update your API base URL to `https://api.payfonte.com`.
Confirm your production webhook URL is configured under `Settings -> Security -> API Keys and Webhooks`.
## Recommended App Configuration
Use environment variables so secrets stay out of source code:
```bash theme={null}
# Sandbox
PAYFONTE_SANDBOX_BASE_URL=https://sandbox-api.payfonte.com
PAYFONTE_SANDBOX_CLIENT_ID=...
PAYFONTE_SANDBOX_CLIENT_SECRET=...
# Production
PAYFONTE_PRODUCTION_BASE_URL=https://api.payfonte.com
PAYFONTE_PRODUCTION_CLIENT_ID=...
PAYFONTE_PRODUCTION_CLIENT_SECRET=...
```
```javascript theme={null}
const isProduction = process.env.NODE_ENV === "production";
const config = isProduction
? {
baseUrl: process.env.PAYFONTE_PRODUCTION_BASE_URL,
clientId: process.env.PAYFONTE_PRODUCTION_CLIENT_ID,
clientSecret: process.env.PAYFONTE_PRODUCTION_CLIENT_SECRET,
}
: {
baseUrl: process.env.PAYFONTE_SANDBOX_BASE_URL,
clientId: process.env.PAYFONTE_SANDBOX_CLIENT_ID,
clientSecret: process.env.PAYFONTE_SANDBOX_CLIENT_SECRET,
};
```
## Security Notes
* Never expose `client-secret` in frontend apps.
* Never commit credentials to git.
* Rotate keys immediately if you suspect exposure.
* Use HTTPS for API and webhook endpoints.
# Error Codes
Source: https://docs.payfonte.com/en/guides/introductions/error-codes
Common Payfonte API error codes, meanings, and recommended fixes for collection and disbursement flows.
All non-2xx responses include error details in this shape:
```json theme={null}
{
"error": "Human-readable message",
"errorCode": "MachineReadableCode"
}
```
Use both HTTP status and `errorCode` in your handling logic.
## Collection Errors
| Status | Error Code | Meaning | Recommended Action |
| ------ | ------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------- |
| `404` | `CurrencyExchangeValueNotFound` | Exchange value needed for currency conversion is unavailable. | Retry later or use a supported currency/country pair. |
## Disbursement Errors
| Status | Error Code | Meaning | Recommended Action |
| ------ | ---------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------- |
| `404` | `TransferRecipientNotFound` | Transfer recipient does not exist (or was removed). | Re-validate and recreate recipient, then retry. |
| `500` | `InActiveWallet` | disbursement wallet is inactive or on post-no-debit (PND). | Check wallet status on dashboard before retrying. |
| `500` | `InsufficientBalance` | Wallet balance is too low for disbursement. | Fund disbursement wallet and retry. |
| `500` | `InvalidDisbursementConfiguration` | Disbursement setup is incomplete or invalid. | Review disbursement settings in dashboard. |
| `400` | `InvalidDisbursementPin` | Disbursement PIN missing or incorrect. | Set/reset PIN and retry with valid value. |
| `403` | `InvalidDisbursementWhitelistedIP` | Request IP is not whitelisted for disbursement. | Add caller IP to allowlist or route from approved IP. |
| `409` | `TransferRecipientExists` | Recipient already exists. | Reuse existing recipient instead of creating a new one. |
| `400` | `TransferRecipientBlacklisted` | Recipient is blacklisted. | Use another eligible recipient. |
| `422` | `ValidateAuthorizationURLError` | Authorization URL validation failed for disbursement flow. | Check authorization endpoint availability and response behavior. |
| `400` | `RecipientDailyLimitReached` | Recipient daily limit has been exceeded. | Retry later or lower amount if supported. |
| `400` | `DuplicateDisbursementDetected` | Same amount to same recipient detected in short window. | Use unique references and idempotent retry strategy. |
## General Errors
| Status | Error Code | Meaning | Recommended Action |
| ------ | ------------------------------- | -------------------------------------------------------- | ----------------------------------------------------- |
| `409` | `DuplicateTransactionReference` | A request used a previously used reference value. | Generate unique references per transaction. |
| `422` | `ValidationError` | One or more request fields are invalid. | Fix field types/values and retry. |
| `404` | `IntegrationNotFound` | Requested provider integration is not configured/active. | Activate integration in dashboard. |
| `404` | `ResourceNotFound` | Requested resource does not exist. | Verify endpoint path and identifiers. |
| `500` | `InvalidProvider` | Unsupported provider slug passed in request. | Use a valid slug from Supported Providers. |
| `500` | `InternalServerError` | Unexpected server-side failure. | Retry with backoff and contact support if persistent. |
## Fast Troubleshooting Flow
Parse both values first to classify auth, validation, configuration, or processing issues.
Confirm `client-id`, `client-secret`, provider slug, reference uniqueness, and integer minor-unit `amount`.
Confirm wallet status, integration status, disbursement PIN, webhook config, and whitelisted IP settings.
Use idempotent retries with exponential backoff for transient failures.
## Related Docs
Response format, filtering, and API conventions.
Validate provider slugs and market coverage.
Reproduce and validate error scenarios in sandbox.
# FAQ & Features Explained
Source: https://docs.payfonte.com/en/guides/introductions/faq
Frequently asked questions about Africa payment orchestration, mobile money API integration, MTN MoMo API, M-Pesa API, Airtel Money API, and local payment methods in Africa.
Everything you need to know about Payfonte's payment orchestration platform Africa, mobile money API integration, and processing alternative payment methods (APM) across African markets.
***
## Getting Started
Payfonte is a payment orchestration platform Africa and mobile money payment aggregator built specifically for African markets. We enable businesses to accept and disburse payments across 14+ African countries through a single payment orchestration API integration.
Our platform supports all major alternative payment methods (APM) and local payment methods in Africa:
* Mobile Money API: MTN MoMo, Orange Money, Airtel Money, M-Pesa, Wave, Moov
* Bank Transfers: Direct bank payments in Nigeria, Kenya, South Africa
* Cards: Visa, Mastercard via partner gateways
* Digital Wallets: Opay, PalmPay, and others
Key Africa mobile money API integrations include:
* MTN MoMo API integration across 10+ countries
* M-Pesa API for Kenya and Tanzania
* Airtel Money API for pan-African coverage
* Wave Money integration for Senegal, Ivory Coast, and more
With one multi-PSP integration, you can process payments across all these methods and markets with smart payment routing Africa capabilities.
Getting started is simple:
1. Create a Sandbox Account: Sign up at [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com)
2. Get API Credentials: Navigate to Settings -> Security -> API Keys and Webhooks in your dashboard
3. Set Up Webhooks: Configure your callback URL under Settings -> Security -> API Keys and Webhooks
4. Test Your Integration: Use our sandbox environment to test transactions
5. Complete KYB: Submit documentation via our [KYB form](https://form.jotform.com/240038360690048)
6. Go Live: Once approved, switch to production credentials
Typical onboarding time: 1-5 business days after KYB submission.
| Aspect | Sandbox | Production |
| ----------- | ---------------------------------- | -------------------------- |
| API URL | `https://sandbox-api.payfonte.com` | `https://api.payfonte.com` |
| Dashboard | `https://sandbox-app.payfonte.com` | `https://app.payfonte.com` |
| Real Money | ❌ No | ✅ Yes |
| Credentials | Separate sandbox keys | Separate production keys |
| MNO Prompts | Simulated responses | Real STK push/USSD |
Important: Sandbox and Production are completely separate environments. Your sandbox configuration (API tokens, callback URLs, test data) does NOT carry over to production. You must reconfigure everything when going live.
Our KYB (Know Your Business) requirements vary by business type, but typically include:
For Companies:
* Certificate of Incorporation
* Memorandum & Articles of Association
* Board Resolution authorizing payment processing
* Valid ID of Directors/UBOs
* Proof of Business Address
* Bank Statement (last 3 months)
For Sole Proprietors:
* Business Registration Certificate
* Valid Government ID
* Proof of Address
* Bank Statement
Processing Time: 1-5 business days
We offer relaxed KYB requirements compared to direct MNO integrations. Some merchants have completed onboarding in as little as 5 minutes for straightforward applications.
***
## Mobile Money API Explained
Mobile money is a core alternative payment method (APM) where users pay directly from their mobile wallet (MTN MoMo, M-Pesa, Orange Money, Airtel Money, Wave, etc.) without needing a bank account or card. This is the most popular local payment method in Africa.
The typical payment flow using our mobile money API:
```mermaid theme={null}
sequenceDiagram
participant Customer
participant Merchant
participant Payfonte
participant MNO
Merchant->>Payfonte: Create checkout session
Payfonte-->>Merchant: Return checkout URL
Merchant->>Customer: Redirect to checkout
Customer->>Payfonte: Select mobile money, enter phone
Payfonte->>MNO: Initiate payment request
MNO->>Customer: Send STK Push / USSD prompt
Customer->>MNO: Enter PIN to authorize
MNO-->>Payfonte: Payment confirmed
Payfonte->>Merchant: Webhook notification
Payfonte->>Customer: Redirect to success URL
```
The entire process typically takes 30-60 seconds from initiation to confirmation.
These are two methods MNOs use to prompt customers to authorize payments through their mobile money API:
### STK Push (SIM Toolkit Push)
* How it works: A payment prompt is automatically "pushed" to the customer's phone
* User experience: Customer sees a pop-up asking them to enter their PIN
* Supported by: M-Pesa API (Kenya, Tanzania), some MTN markets
* Pros: Seamless, no dialing required
* Cons: Requires phone to be on and have signal
### USSD (Unstructured Supplementary Service Data)
* How it works: Customer dials a code or receives a session-based menu
* User experience: Customer navigates menu and enters PIN
* Supported by: MTN MoMo API, Orange Money, Airtel Money API
* Pros: Works on basic phones, no data required
* Cons: More steps for customer
### Provider Authorization (Merchant-Initiated)
* How it works: Payment request sent directly via mobile money API, MNO prompts customer
* Supported by: Most alternative payment method providers in West Africa
* Pros: Consistent experience across channels
Payfonte's payment orchestration API automatically selects the appropriate authorization method based on the provider and country. You don't need to handle this logic—just call our API and we manage the mobile money integration Africa complexity.
When a customer pays via mobile money through Payfonte:
Step 1: Initiation
* Customer selects mobile money as payment method
* Enters their mobile money phone number
* Clicks "Pay"
Step 2: Authorization
* Customer receives an STK push notification OR USSD prompt on their phone
* The prompt shows: merchant name, amount, and reference
* Customer enters their mobile money PIN to authorize
Step 3: Confirmation
* Customer sees "Payment Successful" on their phone
* Receives SMS confirmation from MNO
* Redirected back to merchant's success page
Typical Timing:
| Stage | Duration |
| ---------------------- | ------------- |
| Initiation to prompt | 2-5 seconds |
| Customer authorization | 10-30 seconds |
| Confirmation callback | 1-3 seconds |
| Total | 15-45 seconds |
Some MNO integrations support pre-authorization, where the customer pre-approves a payment before the merchant initiates it.
How it works:
1. Customer visits MNO app/USSD and generates a pre-authorization code
2. Customer provides this code to the merchant
3. Merchant includes `preAuthorisationCode` in the API request
4. Payment is processed without additional prompts
Supported markets:
* Orange Burkina Faso
* Orange Senegal
Pre-authorization availability depends on the specific MNO and market. Contact support for the latest supported configurations.
***
## Transaction Processing
Payfonte transactions can have the following statuses:
| Status | Description | Final? | Action Required |
| ------------ | -------------------------------------------------- | ------ | ----------------- |
| `queued` | Payment Queued for Processing | ❌ | Wait for webhook |
| `pending` | Payment initiated, awaiting customer authorization | ❌ | Wait for webhook |
| `processing` | Customer authorized, MNO processing | ❌ | Wait for webhook |
| `success` | Payment completed successfully | ✅ | Fulfill order |
| `rejected` | Payment failed (see error code) | ✅ | Show retry option |
| `failed` | Payment failed (see error code) | ✅ | Show retry option |
| `expired` | Customer didn't authorize in time | ✅ | Show retry option |
| `reversed` | Funds returned to customer | ✅ | Update records |
Never fulfill orders based on `pending` or `processing` status. Always wait for a final status (`success`, `failed`, `expired`) before taking action.
Our Smart Reconciliation Engine ensures every transaction reaches a final status:
How it works:
1. Real-time monitoring: We track every transaction from initiation
2. Automatic polling: For pending transactions, we poll MNO status APIs
3. Statement reconciliation: We download and reconcile MNO statements
4. Timeout handling: Transactions that exceed timeout are marked appropriately
5. Callback retry: We retry webhook notifications until acknowledged or after 60 minute
Result: No transaction is left in `pending` state indefinitely. Every payment reaches a conclusive status (success, failed, or expired) within the provider's timeout window (typically 5-60 minutes).
If you see a transaction stuck in "pending" on your dashboard, our reconciliation engine is already working to resolve it. Check back in 5-60 minutes, or contact support if it persists beyond 60 minutes.
Each MNO has different timeout windows for customer authorization:
| Provider | Timeout | Notes |
| -------------- | ------------ | ------------------------ |
| M-Pesa (Kenya) | 60 seconds | STK push expires quickly |
| MTN MoMo | 5-15 minutes | Varies by country |
| Orange Money | 5-10 minutes | USSD session timeout |
| Airtel Money | 5-10 minutes | Standard timeout |
| Wave | 5 minutes | App-based confirmation |
If a customer doesn't authorize within the timeout window, the transaction will be marked as `expired` and you'll receive a webhook notification.
When a transaction fails, check the `errorCode` and `errorMessage` in the response/webhook:
Common failure reasons:
| Error | Cause | Resolution |
| ---------------------- | -------------------------------------------- | -------------------------- |
| `INSUFFICIENT_FUNDS` | Customer's wallet balance too low | Ask customer to top up |
| `WRONG_PIN` | Customer entered incorrect PIN | Retry with correct PIN |
| `TIMEOUT` | Customer didn't respond in time | Retry the transaction |
| `ACCOUNT_LOCKED` | Customer's wallet is locked | Customer contacts MNO |
| `INVALID_PHONE` | Phone number not registered for mobile money | Verify phone number |
| `DAILY_LIMIT_EXCEEDED` | Customer exceeded daily transaction limit | Try smaller amount or wait |
| `SYSTEM_ERROR` | MNO technical issue | Retry after a few minutes |
Best practices:
* Show user-friendly error messages
* Offer retry option for retriable errors
* Log all failed transactions for analysis
* Contact support for persistent `SYSTEM_ERROR` issues
***
## Webhooks & Callbacks
Webhooks notify your server about transaction status changes in real-time.
Setup steps:
1. Go to Dashboard → Settings -> Security -> API Keys and Webhooks
2. Enter your webhook endpoint URL (e.g., `https://yoursite.com/payfonte/webhook`)
3. Click Save
Requirements for your webhook endpoint:
* Must be publicly accessible (no localhost)
* Must use HTTPS (SSL certificate required)
* Must return HTTP 200 within 30 seconds
* Should be idempotent (handle duplicate calls)
You can also specify a webhook URL per-transaction by including the `webhook` parameter in your API request. This overrides the default webhook for that specific transaction.
When a transaction status changes, we send a POST request to your webhook URL:
```json theme={null}
{
"event": "payment.completed",
"timestamp": "2025-02-06T10:30:00Z",
"data": {
"reference": "ORDER-12345",
"checkoutId": "chk_abc123xyz",
"amount": 5000,
"currency": "NGN",
"country": "NG",
"status": "success",
"provider": "mtn-momo-nigeria",
"channel": "mobile-money",
"user": {
"email": "customer@example.com",
"phoneNumber": "08012345678"
},
"paidAt": "2025-02-06T10:30:00Z",
"metadata": {
"orderId": "your-custom-data"
}
}
}
```
Event types:
* `payment.completed` - Payment successful
* `payment.failed` - Payment failed
* `payment.expired` - Payment timed out
* `disbursement.completed` - Disbursement successful
* `disbursement.failed` - Disbursement failed
Best practices for webhook handling:
```javascript theme={null}
app.post('/payfonte/webhook', async (req, res) => {
const event = req.body;
// 1. Acknowledge immediately (prevents timeout)
res.status(200).send('OK');
// 2. Process asynchronously
processWebhookAsync(event);
});
async function processWebhookAsync(event) {
// 3. Check if already processed (idempotency)
const existing = await db.findTransaction(event.data.reference);
if (existing?.status === event.data.status) {
return; // Already processed
}
// 4. Verify transaction via API (optional but recommended)
const verified = await payfonte.verifyTransaction(event.data.reference);
// 5. Update your records
await db.updateTransaction(event.data.reference, {
status: verified.status,
paidAt: verified.paidAt
});
// 6. Take action
if (verified.status === 'success') {
await fulfillOrder(event.data.reference);
}
}
```
Critical: Always return HTTP 200 quickly. If your endpoint times out or returns an error, we'll retry the webhook. Implement idempotency to handle duplicate deliveries.
We implement automatic retry logic for failed webhook deliveries:
Retry schedule:
* Attempt 1: Immediate
* Attempt 2: 1 minute later
* Attempt 3: 5 minutes later
* Attempt 4: 30 minutes later
* Attempt 5: 1 hours later
After all retries fail:
* Transaction status is still updated in our system
* You can always query transaction status via API
* Replay the webhooks from your dashboard
Set up monitoring for your webhook endpoint and dashboard alerts for failed deliveries. You can also implement a polling fallback to check for missed webhooks.
***
## Settlement & Disbursements
Settlement times vary by country and payment method:
| Country | Method | Settlement |
| -------------- | ------------- | ----------------------- |
| Nigeria | Bank Transfer | T+1 (Next business day) |
| Nigeria | Mobile Money | T+1 to T+2 |
| Kenya | M-Pesa | T+1 |
| Ghana | All methods | T+1 to T+2 |
| Ivory Coast | Mobile Money | T+2 to T+3 |
| Other CFA Zone | Mobile Money | T+2 to T+3 |
T = Settlement Request Day
Settlements are processed to your designated bank account or mobile money wallet as configured in your merchant profile.
Yes! Payfonte supports disbursements to:
* Mobile Money Wallets: Send to any supported MNO
* Bank Accounts: Nigeria, Kenya, South Africa, and more
* Bulk Disbursements: Process multiple disbursements in one API call
Process:
1. Validate recipient (phone number or bank account)
2. Submit disbursement request
3. Receive webhook on completion
Typical processing times:
* Mobile Money: 30 seconds - 5 minutes
* Bank Transfer: Same day - Next business day
See our [Disbursements Guide](/en/guides/disbursements/overview) for full documentation.
You can check your wallet balances via:
Dashboard:
* Login to your merchant dashboard
* View balances on the home screen
* You can switch country by using the switch on the top right to view balances in a different country
API:
```bash theme={null}
curl --location 'https://api.payfonte.com/billing/v1/wallets' \
--header 'client-id: YOUR_CLIENT_ID' \
--header 'client-secret: YOUR_CLIENT_SECRET'
```
Response shows balances per currency:
```json theme={null}
{
"data": [
{ "currency": "NGN", "country": "NG", "balance": 1500000 },
{ "currency": "KES", "country": "KE", "balance": 85000 },
{ "currency": "XOF", "country": "CI", "balance": 2500000 }
]
}
```
***
## Technical Integration - Payment Orchestration API
Payfonte does not support decimal amounts. Send integer values only in minor units.
Examples:
| Display Amount | Value to Send |
| -------------- | ------------- |
| `5000.50 NGN` | `500050` |
| `100.00 GHS` | `10000` |
| `1000 KES` | `100000` |
| `10000 XOF` | `1000000` |
| `5000 XAF` | `500000` |
Important: Sending decimals (for example `1250.75`) will cause validation or provider failures. Send minor-unit integers only (for example `125075`).
See [Amount Specification](/en/guides/introductions/amount-specification) for full conversion guidance, and [Supported Providers](/en/guides/introductions/supported-providers) for provider limits.
Phone numbers should be in international format without the plus sign:
| Country | Format | Example |
| ----------- | ------------- | --------------- |
| Nigeria | 234XXXXXXXXXX | `2348012345678` |
| Kenya | 254XXXXXXXXX | `254712345678` |
| Ghana | 233XXXXXXXXX | `233201234567` |
| Ivory Coast | 225XXXXXXXXXX | `2250512345678` |
| Cameroon | 237XXXXXXXXX | `237612345678` |
Do NOT include:
* Plus sign (+)
* Spaces or dashes
* Leading zeros after country code
Example:
```json theme={null}
// ✅ Correct
{ "phoneNumber": "2348012345678" }
// ❌ Wrong
{ "phoneNumber": "+234-801-234-5678" }
{ "phoneNumber": "08012345678" }
```
The Direct Charge payment orchestration API allows you to initiate payments directly without redirecting customers to a checkout page. This is useful for:
* Server-to-server payments: When you've already collected customer details for mobile money API charges
* Recurring payments: Charging saved payment methods
* Mobile app integrations: Native mobile money integration Africa experiences
How it works with MTN MoMo API, M-Pesa API, and other mobile money:
```bash theme={null}
curl --location 'https://api.payfonte.com/payments/v1/payments/direct-charge' \
--header 'client-id: YOUR_CLIENT_ID' \
--header 'client-secret: YOUR_CLIENT_SECRET' \
--header 'Content-Type: application/json' \
--data '{
"provider": "mtn-momo-nigeria",
"amount": 5000,
"reference": "ORDER-12345",
"customerInput": {
"phoneNumber": "2348012345678"
},
"webhook": "https://yoursite.com/webhook"
}'
```
The customer receives the STK push / USSD prompt directly on their phone through the Africa mobile money API.
Yes! Bring Your Own Keys (BYOK) or Hybrid Orchestration is our multi-PSP integration Africa approach that lets you use your existing MNO contracts through Payfonte's payment orchestration platform infrastructure.
How it works:
* You maintain direct contracts with MNOs (e.g., MTN MoMo API, M-Pesa API, Orange Money)
* Securely input your MNO’s API keys, this gets tokenised and stored encrypted and not visible to Payfonte
* We route transactions through your MNO wallet/account/OVA using our smart payment routing engine
* You keep your negotiated rates for each mobile money API
Benefits of multi-PSP integration:
* Lower fees (your negotiated rates)
* Maintain provider relationships
* Combined coverage (your contracts + our partnerships)
* Single dashboard for all alternative payment methods (APM)
* Enterprise payment orchestration Africa capabilities
Setup:
Contact [commercial@payfonte.com](mailto:commercial@payfonte.com) to configure hybrid orchestration for your Africa payment orchestration account.
Payfonte's smart payment routing Africa technology provides automatic failover:
How it works:
1. When a primary provider fails, we automatically try backup rails
2. Multi-PSP integration ensures multiple providers per country for redundancy
3. Real-time monitoring detects outages within seconds
4. Traffic is re-routed without merchant intervention
Example for mobile money API failover:
* Primary: MTN MoMo API direct integration
* Backup 1: MTN via aggregator
* Backup 2: Alternative mobile money payment aggregator route
Result: 99.99% uptime and higher transaction success rates across all local payment methods in Africa.
You can also configure routing preferences in your dashboard if you want to prioritize certain alternative payment methods for cost or performance reasons.
***
## Security & Compliance
Yes. Payfonte is PCI DSS compliant and undergoes regular security assessments:
* PCI DSS Compliance: We are strictly compliant with the PCIDSS standard for card security
* Quarterly ASV Scans: External vulnerability assessments by certified consultants
* Annual Penetration Testing: Third-party security audits
* End-to-End Encryption: All data encrypted in transit (TLS 1.2+) and at rest
You can request our compliance certificates via [compliance@payfonte.com](mailto:compliance@payfonte.com).
We take data privacy seriously:
* GDPR-aligned practices: Even for non-EU data
* Data minimization: We only collect what's necessary
* Encryption: All PII encrypted at rest and in transit
* Access controls: Role-based access with audit logging
* Retention policies: Data retained per regulatory requirements
Customer data we store:
* Phone numbers (for payment processing)
* Email addresses (for notifications)
* Transaction history (for reconciliation)
We do NOT store:
* Mobile money PINs
* Card CVVs (tokenized immediately)
* Customer wallet balances
Payfonte includes built-in fraud detection:
* Velocity checks: Detect unusual transaction patterns
* Device fingerprinting: Identify suspicious devices
* Geolocation analysis: Flag location mismatches
* Amount thresholds: Configurable limits per merchant
* Blacklist management: Block known bad actors
You can also:
* Set custom transaction limits in your dashboard
* Enable additional verification for high-value transactions
* Access fraud analytics and reports
***
## Troubleshooting
Transactions may appear pending for several reasons:
| Cause | Resolution |
| ------------------------------ | -------------------------------------- |
| Customer hasn't authorized yet | Wait for customer to enter PIN |
| MNO processing delay | Usually resolves within 5-15 minutes |
| Network connectivity issues | Our reconciliation engine will resolve |
| STK push not received | Customer may need to retry |
What to do:
1. Wait 5-15 minutes for auto-resolution
2. Check transaction status via API
3. If stuck > 30 minutes, contact support
Our reconciliation engine ensures all transactions reach final state—no manual intervention required in most cases.
This error means your API credentials are invalid:
Common causes:
* Using sandbox credentials with production URL (or vice versa)
* Typo in `client-id` or `client-secret`
* Credentials were regenerated and old ones are being used
* Missing required headers
Solution:
1. Verify you're using the correct environment URLs
2. Re-copy credentials from Dashboard → Settings → API Keys
3. Ensure headers are exactly: `client-id` and `client-secret` (not `clientId`)
```bash theme={null}
# Correct header format
--header 'client-id: abc123' \
--header 'client-secret: xyz789'
```
Our sandbox supports testing various scenarios using test phone numbers.
[//]: # "| Phone Number | Scenario |"
[//]: # "|--------------|----------|"
[//]: # "| `2348000000001` | Successful payment |"
[//]: # "| `2348000000002` | Failed - Insufficient funds |"
[//]: # "| `2348000000003` | Failed - Wrong PIN |"
[//]: # "| `2348000000004` | Timeout - No response |"
[//]: # "| `2348000000005` | Processing delay (30s) |"
[//]: #
[//]: # "Use these numbers with any supported provider slug in sandbox to simulate different outcomes."
See our [Testing Guide](/en/guides/introductions/testing) for complete test scenarios.
***
## Still Have Questions?
[support@payfonte.com](mailto:support@payfonte.com)
Schedule a walkthrough
Full API documentation
# Overview
Source: https://docs.payfonte.com/en/guides/introductions/overview
Africa payment orchestration platform - Mobile money API integration for MTN MoMo, M-Pesa, Airtel Money, Wave. Accept local payment methods across 14+ African markets with one API.
We provide the infrastructure for integrating Alternative Payment Methods (APM) and local payment methods in Africa—including mobile money, bank transfers, and cards—through one multi-PSP integration. Our platform offers smart payment routing and enterprise payment orchestration capabilities designed specifically for African markets.
## Why Payfonte?
Our Africa payment orchestration platform provides everything you need to accept local payment methods in Africa:
Use your existing MNO contracts where you have better rates, or leverage Payfonte's direct partnerships. Our multi-PSP integration Africa approach lets you combine both for optimal coverage and cost efficiency across all markets.
Eliminate the cost of developing and maintaining individual mobile money API
integrations in-house. No MTN MoMo API integration, M-Pesa API, or Airtel
Money API development needed—we handle the infrastructure.
Our smart payment routing Africa technology provides automatic failover and
backup rails ensuring maximum transaction success rates. The routing engine
selects the optimal path for each transaction across your alternative payment
methods (APM).
One dashboard for all markets, payment methods, and MNOs. Manage your entire
mobile money integration Africa portfolio with streamlined payment operations,
financial reconciliation, and real-time reporting.
In-built reconciliation engine ensures 100% final state resolution. No missing
or hanging transactions—every payment reaches a definitive status across all
your Africa mobile money API integrations.
Fully customizable checkout pages with your branding, or complete Payment Infrastructure-as-a-Service for fintechs building enterprise payment orchestration Africa solutions.
***
## Our Products
Payfonte offers two primary product lines to meet different business needs:
For Fintechs & Enterprises
Full payment infrastructure on your own MNO contracts. We provide the technology layer—you maintain direct relationships with providers.
* Use your own MNO/PSP contracts
* White-label checkout & dashboard
* Complete API access
* Custom routing rules
For Merchants & Businesses
Start accepting payments immediately using Payfonte's aggregated MNO partnerships. No direct contracts required.
* Instant go-live capability
* Pre-negotiated MNO rates
* Simplified onboarding
* Managed compliance
***
## Quick Start Guide
Get up and running in three simple steps:
Sign up at [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com) to access your test environment.
Navigate to Settings -> Security -> API Keys and Webhooks in your dashboard to retrieve your `client-id` and `client-secret`.
Use the sandbox base URL to test your integration:
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "test-001",
"amount": 1000,
"currency": "NGN",
"country": "NG",
"redirectURL": "https://yoursite.com/callback",
"user": {
"email": "customer@example.com",
"phoneNumber": "08012345678"
}
}'
```
Ready for production? Complete the KYB process via our [onboarding
form](https://form.jotform.com/240038360690048) and go live in 1-5 business
days.
***
## Supported Alternative Payment Methods (APM)
Payfonte supports comprehensive local payment methods in Africa through our mobile money payment aggregator:
| Category | Providers |
| ---------------- | --------------------------------------------------------------------------- |
| Mobile Money API | MTN MoMo, Orange Money, Airtel Money, M-Pesa, Wave, Moov, Togocel, Halopesa |
| Bank Transfers | Direct bank transfers (Nigeria, Kenya, South Africa) |
| Cards | Visa, Mastercard (via partner gateways) |
| Wallets | Opay, PalmPay, OPay Wallet |
Our Africa mobile money API integrations include:
* MTN MoMo API integration across 10+ countries
* M-Pesa API for Kenya, Tanzania, and other East African markets
* Airtel Money API for pan-African coverage
* Wave Money integration for West Africa
* Orange Money, Moov, and other regional providers
Complete list of supported alternative payment methods by country
Amount formatting rules (integer minor-unit values only, no decimals)
***
## Security & Compliance
Full Payment Card Industry Data Security Standard compliance
External vulnerability assessments by certified security consultants
All data encrypted in transit and at rest
Card data tokenized for recurring payments
***
## Need Help?
Complete API documentation
[support@payfonte.com](mailto:support@payfonte.com)
Schedule a walkthrough
# Platform Overview
Source: https://docs.payfonte.com/en/guides/introductions/platform-overview
Understand how to integrate with Payfonte using Dashboard, APIs, Webhooks, and hosted checkout flows.
Payfonte gives you multiple integration paths so your team can start quickly, then scale into deeper API control when needed.
## Ecosystem At A Glance
Configure providers, monitor transactions, manage disbursements, and control team access from one place.
Build server-to-server payment and disbursement flows with full automation and event callbacks.
Send customers to a Payfonte-hosted payment page with local payment methods and minimal integration effort.
## How Developers Use Payfonte
The dashboard is the fastest way to begin. You can create your account, configure collection or disbursement providers, set webhook URLs, and invite teammates with roles and permissions.
This is ideal when you want to go live quickly without building everything from scratch.
Payfonte APIs let you control checkout creation, direct charge, transaction verification, disbursements, and wallet operations from your backend.
Use this path when you need advanced control, custom business logic, or tight integration with your internal systems.
Hosted checkout is PCI-friendly and supports multiple African payment methods out of the box. You create a checkout session and redirect your customer to complete payment.
You can still receive webhook events and reconcile everything through API or dashboard.
## Integration Paths
| Path | Best For | Effort |
| -------------------------- | -------------------------------------- | ----------- |
| Dashboard-first | Fast setup and operations | Low |
| Hosted checkout + webhooks | Quick launch with async status updates | Low-Medium |
| Full API integration | Deep customization and automation | Medium-High |
## Recommended Rollout
Create your account and configure test providers and webhooks in sandbox.
Start with hosted checkout or inline flow, then move to direct charge/API where needed.
Treat webhook events as the source of truth for transaction lifecycle updates.
Complete KYB, switch base URL and keys, and monitor first live transactions in dashboard.
## Where To Go Next
Build your first successful API call.
Compare inline, standard, and direct charge methods.
Explore endpoints, schemas, and request examples.
# Products
Source: https://docs.payfonte.com/en/guides/introductions/products
Payment orchestration API, Infrastructure-as-a-Service, and mobile money payment aggregator solutions for African markets. Multi-PSP integration with MTN MoMo API, M-Pesa API, Airtel Money API.
Payfonte offers flexible payment orchestration API solutions designed to meet the needs of different business models—from startups accepting their first alternative payment method (APM) to enterprises building full-fledged Africa payment orchestration infrastructure.
***
## Payment Orchestration / Infrastructure-as-a-Service
[//]: # ""
[//]: #
[//]: # " "
[//]: #
[//]: # ""
### Overview
Payment Orchestration (also known as Payment Infrastructure-as-a-Service or PIaaS) is our enterprise payment orchestration Africa solution designed for fintechs, large enterprises, and businesses that have or want to establish direct contracts with Mobile Network Operators (MNOs) and Payment Service Providers (PSPs).
Payfonte provides the payment orchestration API technology layer—API, dashboard, reconciliation engine, and smart payment routing Africa logic—while you maintain ownership of your provider relationships and negotiate your own rates for MTN MoMo API integration, M-Pesa API, Airtel Money API, and other mobile money API connections.
### Who Is This For?
Building payment products and need robust infrastructure without building from scratch
Processing high volumes and want to leverage existing provider contracts
Extending digital payment capabilities to customers
Building their own payment aggregation business
### Key Features
Bring Your Own Contracts: Connect your existing MNO/PSP contracts to Payfonte's payment orchestration platform Africa infrastructure. Our multi-PSP integration Africa approach lets you use Payfonte's partnerships to fill coverage gaps.
* Configure which providers to use per country/method
* Set routing priority and fallback rules for smart payment routing
* Optimize for cost or success rate across all mobile money integration Africa
Fully branded merchant portal for your customers using our enterprise payment orchestration platform:
* Your logo and color scheme
* Custom domain (e.g., payments.yourcompany.com)
* Branded email notifications
* Custom support contact details
Full programmatic control over all payment operations through our payment orchestration API:
* Collections API supporting all alternative payment methods (APM)
* Disbursements API (single and bulk disbursements)
* Webhooks for real-time notifications
* Transaction query and reporting APIs
* Africa mobile money API integrations for all major providers
Automated reconciliation across all connected providers in your Africa payment orchestration setup:
* Real-time transaction status updates
* Automatic retry logic for pending transactions
* 100% final state resolution guarantee
* Detailed reconciliation reports for MTN MoMo API, M-Pesa API, Airtel Money API, and all other integrations
### Getting Started with Payment Orchestration
Reach out to [commercial@payfonte.com](mailto:commercial@payfonte.com) or [book a demo](https://calendly.com/payfonte-onboarding/30min) to discuss your requirements.
Share details of your existing provider contracts (if any) so we can configure your routing.
Integrate with our API using the sandbox environment. Our team will assist with configuration.
Complete compliance review and launch in production.
***
## Payment Aggregation
### Overview
Payment Aggregation is Payfonte's turnkey mobile money payment aggregator solution for businesses that want to start accepting local payment methods in Africa immediately without establishing direct contracts with MNOs. We act as the aggregator, providing access to our pre-negotiated partnerships across all supported markets for MTN MoMo API integration, M-Pesa API, Wave Money integration, Airtel Money API, and other alternative payment methods (APM).
### Who Is This For?
Online stores accepting payments from African customers
Software businesses with African user bases
Platforms collecting payments on behalf of sellers
Early-stage companies needing fast time-to-market
### Key Features
Start accepting local payment methods in Africa within days of onboarding:
* No MNO contract negotiations required for mobile money API access
* Pre-configured alternative payment methods per country
* Automatic provider selection and smart payment routing Africa
Transparent, predictable pricing for all mobile money integration Africa:
* Single fee per transaction
* No hidden costs or setup fees
* Volume-based discounts available
We handle regulatory complexity for your Africa payment orchestration:
* KYB verification process
* AML/CFT compliance monitoring
* Local regulatory requirements
Multiple integration methods for Africa mobile money API payments:
* Hosted Checkout: Redirect customers to Payfonte-hosted payment page
* Inline Checkout: Embed payment form on your website
* Payment Links: Generate shareable payment URLs
* Direct API: Full control via payment orchestration API calls
[//]: #
[//]: # "### Getting Started with Payment Aggregation"
[//]: #
[//]: # ""
[//]: # " "
[//]: # " Sign up at [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com) to test the integration."
[//]: # " "
[//]: #
[//]: # " "
[//]: # " Follow our [Quick Start Guide](/en/guides/introductions/quick-start) to make your first test transaction."
[//]: # " "
[//]: #
[//]: # " "
[//]: # " Submit required documentation via our [onboarding form](https://form.jotform.com/240038360690048)."
[//]: # " "
[//]: #
[//]: # " "
[//]: # " Once approved, switch to production credentials and start accepting real payments."
[//]: # " "
[//]: # ""
[//]: #
[//]: # "---"
[//]: #
[//]: # "## Product Comparison"
[//]: #
[//]: # "| Feature | Payment Orchestration / IaaS | Payment Aggregation |"
[//]: # "|---------|------------------------------|---------------------|"
[//]: # "| Use Your Own MNO Contracts | ✅ Yes | ❌ No |"
[//]: # "| Use Payfonte's Partnerships | ✅ Optional | ✅ Required |"
[//]: # "| White-Label Dashboard | ✅ Full customization | ❌ Standard branding |"
[//]: # "| Custom Smart Payment Routing | ✅ Full control | ❌ Automatic |"
[//]: # "| Multi-PSP Integration | ✅ Unlimited providers | Pre-configured |"
[//]: # "| Time to Go Live | 2-4 weeks | 1-5 days |"
[//]: # "| Best For | Fintechs, Enterprises | SMBs, Startups |"
[//]: # "| Pricing Model | Platform fee + your provider costs | Transaction fee |"
[//]: #
[//]: # "Both products provide access to our full suite of Africa mobile money API integrations including MTN MoMo API, M-Pesa API, Wave Money integration, and Airtel Money API."
[//]: #
[//]: # "---"
[//]: #
[//]: # "## Not Sure Which Product Fits?"
[//]: #
[//]: # ""
[//]: # " Schedule a 30-minute consultation to discuss your use case and get a personalized recommendation."
[//]: # ""
# Quick Start
Source: https://docs.payfonte.com/en/guides/introductions/quick-start
Get up and running with Payfonte payment orchestration API in under 10 minutes. Integrate MTN MoMo API, M-Pesa API, and other Africa mobile money API providers.
This guide will help you make your first payment orchestration API call to Payfonte in under 10 minutes. By the end, you'll have integrated Africa mobile money API capabilities including MTN MoMo API, M-Pesa API, and other local payment methods in Africa.
***
## Prerequisites
Before you begin, you'll need:
A Payfonte sandbox accountYour API credentials (client-id and client-secret)
A tool to make HTTP requests (cURL, Postman, or your preferred language)
***
## Step 1: Create Your Sandbox Account
Go to [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com) and create a free account.
Check your inbox and verify your email address.
Fill in basic business information to activate your account.
***
## Step 2: Get Your API Credentials
Log into your dashboard and click on Settings in the sidebar.
Click on API Keys/Webhooks tab.
You'll find your:
* `client-id` - Your unique identifier
* `client-secret` - Your secret key (keep this secure!)
Never expose your `client-secret` in client-side code or public repositories.
Always make API calls from your backend server.
***
## Step 3: Set Up Webhook Callback (Optional but Recommended)
Webhooks notify your server about transaction status changes in real-time.
In Settings -> Security -> API Keys and Webhooks, find the webhook configuration section.
Add your webhook endpoint URL (e.g., `https://yoursite.com/payfonte/webhook`).
Click Save. You can test the webhook using our test transaction feature.
***
## Environment URLs
Use these URLs for development and testing:
| Service | URL |
| ------------- | --------------------------------------- |
| API Base URL | `https://sandbox-api.payfonte.com` |
| Dashboard | `https://sandbox-app.payfonte.com` |
| Checkout Page | `https://sandbox-checkout.payfonte.com` |
Sandbox transactions are simulated and do not involve real money.
Use these URLs for live transactions:
| Service | URL |
| ------------- | ------------------------------- |
| API Base URL | `https://api.payfonte.com` |
| Dashboard | `https://app.payfonte.com` |
| Checkout Page | `https://checkout.payfonte.com` |
Production transactions involve real money. Ensure thorough testing in sandbox first.
***
## Step 4: Make Your First API Call
Let's create a checkout session to collect a payment:
```bash cURL theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: YOUR_CLIENT_ID' \
--header 'client-secret: YOUR_CLIENT_SECRET' \
--header 'Content-Type: application/json' \
--data-raw '{
"reference": "order-001",
"amount": 5000,
"currency": "NGN",
"country": "NG",
"redirectURL": "https://yoursite.com/payment/success",
"webhook": "https://yoursite.com/payfonte/webhook",
"user": {
"email": "customer@example.com",
"phoneNumber": "08012345678"
}
}'
```
```javascript Node.js theme={null}
const axios = require("axios");
const response = await axios.post(
"https://sandbox-api.payfonte.com/payments/v1/checkouts",
{
reference: "order-001",
amount: 5000,
currency: "NGN",
country: "NG",
redirectURL: "https://yoursite.com/payment/success",
webhook: "https://yoursite.com/payfonte/webhook",
user: {
email: "customer@example.com",
phoneNumber: "08012345678",
},
},
{
headers: {
"client-id": "YOUR_CLIENT_ID",
"client-secret": "YOUR_CLIENT_SECRET",
"Content-Type": "application/json",
},
},
);
console.log(response.data);
```
```python Python theme={null}
import requests
url = "https://sandbox-api.payfonte.com/payments/v1/checkouts"
headers = {
"client-id": "YOUR_CLIENT_ID",
"client-secret": "YOUR_CLIENT_SECRET",
"Content-Type": "application/json"
}
payload = {
"reference": "order-001",
"amount": 5000,
"currency": "NGN",
"country": "NG",
"redirectURL": "https://yoursite.com/payment/success",
"webhook": "https://yoursite.com/payfonte/webhook",
"user": {
"email": "customer@example.com",
"phoneNumber": "08012345678"
}
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
```
```php PHP theme={null}
"https://sandbox-api.payfonte.com/payments/v1/checkouts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"client-id: YOUR_CLIENT_ID",
"client-secret: YOUR_CLIENT_SECRET",
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode([
"reference" => "order-001",
"amount" => 5000,
"currency" => "NGN",
"country" => "NG",
"redirectURL" => "https://yoursite.com/payment/success",
"webhook" => "https://yoursite.com/payfonte/webhook",
"user" => [
"email" => "customer@example.com",
"phoneNumber" => "08012345678"
]
])
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
```
### Expected Response
```json theme={null}
{
"success": true,
"data": {
"checkoutId": "chk_abc123xyz",
"checkoutUrl": "https://sandbox-checkout.payfonte.com/chk_abc123xyz",
"reference": "order-001",
"amount": 5000,
"currency": "NGN",
"status": "pending"
}
}
```
***
## Step 5: Redirect Customer to Checkout
Take the `checkoutUrl` from the response and redirect your customer to complete payment:
```javascript theme={null}
// Redirect customer to checkout
window.location.href = response.data.checkoutUrl;
```
The customer will:
1. See available payment methods for their country
2. Select their preferred method (e.g., MTN MoMo, Bank Transfer)
3. Complete the payment
4. Be redirected to your `redirectURL`
***
## Step 6: Handle the Webhook
When the payment status changes, we'll send a POST request to your webhook URL:
```json theme={null}
{
"event": "payment.completed",
"data": {
"reference": "order-001",
"checkoutId": "chk_abc123xyz",
"amount": 5000,
"currency": "NGN",
"status": "successful",
"provider": "mtn-momo-nigeria",
"paidAt": "2025-02-06T10:30:00Z"
}
}
```
Always verify webhook signatures and confirm transaction status via API before
fulfilling orders.
***
## What's Next?
Learn about inline, standard, and direct charge integrations
Send disbursements to mobile money and bank accounts
See available payment methods by country
Complete API documentation
***
## Troubleshooting
Double-check your `client-id` and `client-secret`. Ensure you're using sandbox credentials with the sandbox URL.
Make sure the currency matches the country. For example, Nigeria uses NGN,
Kenya uses KES. See [Supported
Providers](/en/guides/introductions/supported-providers) for valid
combinations.
Ensure your webhook URL is publicly accessible and returns a 200 status code. Check your server logs for incoming requests.
Contact our support team at [support@payfonte.com](mailto:support@payfonte.com)
# Supported Providers by Country
Source: https://docs.payfonte.com/en/guides/introductions/supported-providers
Reference for Payfonte provider coverage by country, provider slug, transaction type, currency, fetch-properties requirement, and published amount limits.
Last updated: September 27, 2026
Use this page to choose the right provider slug for your integration by country, supported flow, and currency.
This page is the source of truth for provider coverage, provider slugs, supported currencies, fetch-properties requirements, and published min/max transaction limits.
## At a Glance
Provider coverage is currently published for 32 countries across West, East, Central, and Southern Africa.
Send the exact `Slug` value in your API payloads when specifying the `provider` field.
Every listed provider slug on this page currently supports both `Collection` and `Disbursement`.
`bank-transfer-nigeria` is the only listed provider that currently requires fetch-properties support.
Payfonte does not support decimal amounts. Send integer amounts only in minor units. For example, `100.50 NGN` becomes `10050`. See [Amount Specification](/en/guides/introductions/amount-specification).
A `—` in any flow-limit column means no limit is currently published on this page. Actual transaction limits are typically set by the provider or MNO and may vary based on the end user's account level, so do not treat `—` as a guarantee that no restriction exists.
## How To Use This Page
Find your country first, then confirm the provider slug that matches your preferred rail in that market.
The `Slug` column contains the machine-readable provider value your API request should send.
Every listed provider supports collection and disbursement, but published limits still vary by slug.
## Quick Lookup
| Market | Currency | Collection Providers | Disbursement Providers | Notes |
| :---------------------------- | :------- | :--------------------------------------------------------------------- | :--------------------------------------------------------------------- | :-------------------------------------------------------------------------------- |
| [Angola](#angola) | `AOA` | Bank Transfer, Multicaixa Express, PayPay | Bank Transfer, Multicaixa Express, PayPay | 3 providers support both flows |
| [Burkina Faso](#burkina-faso) | `XOF` | Moov, Orange | Moov, Orange | 2 providers support both flows |
| [Benin](#benin) | `XOF` | MTN MoMo, Moov | MTN MoMo, Moov | 2 providers support both flows |
| [DR Congo](#dr-congo) | `CDF` | AfriMoney, Airtel, MPesa, Orange | AfriMoney, Airtel, MPesa, Orange | 4 providers support both flows |
| [Congo](#congo) | `XAF` | Airtel, MTN MoMo | Airtel, MTN MoMo | 2 providers support both flows |
| [Ivory Coast](#ivory-coast) | `XOF` | MTN MoMo, Moov, Orange, Wave | MTN MoMo, Moov, Orange, Wave | 4 providers support both flows |
| [Cameroon](#cameroon) | `XAF` | MTN MoMo, Orange | MTN MoMo, Orange | Published min/max limits are available |
| [Gabon](#gabon) | `XAF` | Airtel | Airtel | 1 provider supports both flows |
| [Ghana](#ghana) | `GHS` | AT, MTN MoMo, Telecel | AT, MTN MoMo, Telecel | 3 providers support both flows |
| [Gambia](#gambia) | `GMD` | AfriMoney, Airtel, Wave | AfriMoney, Airtel, Wave | 3 providers support both flows |
| [Guinea](#guinea) | `GNF` | MTN MoMo, Orange | MTN MoMo, Orange | 2 providers support both flows |
| [Kenya](#kenya) | `KES` | Airtel, M-Pesa | Airtel, M-Pesa | 2 providers support both flows |
| [Liberia](#liberia) | `LRD` | MTN MoMo | MTN MoMo | 1 provider supports both flows |
| [Lesotho](#lesotho) | `LSL` | MTN MoMo | MTN MoMo | 1 provider supports both flows |
| [Madagascar](#madagascar) | `MGA` | Airtel | Airtel | 1 provider supports both flows |
| [Mali](#mali) | `XOF` | Moov, Orange | Moov, Orange | 2 providers support both flows |
| [Mozambique](#mozambique) | `MZN` | Movitel e-Mola, Vodacom M-Pesa | Movitel e-Mola, Vodacom M-Pesa | 2 providers support both flows |
| [Namibia](#namibia) | `NAD` | MTN MoMo | MTN MoMo | 1 provider supports both flows |
| [Niger](#niger) | `XOF` | Airtel | Airtel | 1 provider supports both flows |
| [Nigeria](#nigeria) | `NGN` | Airtel, Bank Transfer, CoralPay, MTN MoMo, Opay, PalmPay, card-nigeria | Airtel, Bank Transfer, CoralPay, MTN MoMo, Opay, PalmPay, card-nigeria | 7 providers support both flows; `bank-transfer-nigeria` requires fetch properties |
| [Rwanda](#rwanda) | `RWF` | Airtel, MTN MoMo | Airtel, MTN MoMo | 2 providers support both flows |
| [Seychelles](#seychelles) | `SCR` | Airtel | Airtel | 1 provider supports both flows |
| [Sierra Leone](#sierra-leone) | `SLE` | Orange | Orange | 1 provider supports both flows |
| [Senegal](#senegal) | `XOF` | Mixx by Yas, Orange, Wave | Mixx by Yas, Orange, Wave | 3 providers support both flows |
| [South Sudan](#south-sudan) | `SSP` | MTN MoMo | MTN MoMo | 1 provider supports both flows |
| [Eswatini](#eswatini) | `SZL` | MTN MoMo | MTN MoMo | 1 provider supports both flows |
| [Chad](#chad) | `XAF` | Airtel | Airtel | 1 provider supports both flows |
| [Togo](#togo) | `XOF` | Mixx by Yas, Moov | Mixx by Yas, Moov | 2 providers support both flows |
| [Tanzania](#tanzania) | `TZS` | Airtel, Halopesa, MPesa, Mixx by Yas | Airtel, Halopesa, MPesa, Mixx by Yas | Published min values are available |
| [Uganda](#uganda) | `UGX` | Airtel, MTN MoMo | Airtel, MTN MoMo | 2 providers support both flows |
| [South Africa](#south-africa) | `ZAR` | Electronic Fund Transfer (EFT), MTN MoMo | Electronic Fund Transfer (EFT), MTN MoMo | 2 providers support both flows |
| [Zambia](#zambia) | `ZMW` | Airtel, MTN MoMo, Zamtel | Airtel, MTN MoMo, Zamtel | 3 providers support both flows |
| Market | Currency | Dual-Flow Slugs | Collection-Only Slugs | Disbursement-Only Slugs |
| :----------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------- | :-------------------- | :---------------------- |
| Angola | `AOA` | `bank-transfer-angola`, `multicaixa-angola`, `paypay-angola` | `—` | `—` |
| Burkina Faso | `XOF` | `moov-burkina-faso`, `orange-burkina-faso` | `—` | `—` |
| Benin | `XOF` | `mtn-momo-benin`, `moov-benin` | `—` | `—` |
| DR Congo | `CDF` | `afrimoney-dr-congo`, `airtel-dr-congo`, `mpesa-dr-congo`, `orange-dr-congo` | `—` | `—` |
| Congo | `XAF` | `airtel-congo`, `mtn-momo-congo` | `—` | `—` |
| Ivory Coast | `XOF` | `mtn-momo-ivory-coast`, `moov-ivory-coast`, `orange-ivory-coast`, `wave-ivory-coast` | `—` | `—` |
| Cameroon | `XAF` | `mtn-momo-cameroon`, `orange-cameroon` | `—` | `—` |
| Gabon | `XAF` | `airtel-gabon` | `—` | `—` |
| Ghana | `GHS` | `airtel-ghana`, `mtn-momo-ghana`, `telecel-ghana` | `—` | `—` |
| Gambia | `GMD` | `afrimoney-gambia`, `airtel-gambia`, `wave-gambia` | `—` | `—` |
| Guinea | `GNF` | `mtn-momo-guinea-conakry`, `orange-guinea-conakry` | `—` | `—` |
| Kenya | `KES` | `airtel-kenya`, `safaricom-kenya` | `—` | `—` |
| Liberia | `LRD` | `mtn-momo-liberia` | `—` | `—` |
| Lesotho | `LSL` | `mtn-momo-lesotho` | `—` | `—` |
| Madagascar | `MGA` | `airtel-madagascar` | `—` | `—` |
| Mali | `XOF` | `moov-mali`, `orange-mali` | `—` | `—` |
| Mozambique | `MZN` | `emola-mozambique`, `mpesa-mozambique` | `—` | `—` |
| Namibia | `NAD` | `mtn-momo-namibia` | `—` | `—` |
| Niger | `XOF` | `airtel-niger` | `—` | `—` |
| Nigeria | `NGN` | `airtel-smartcash-ng`, `bank-transfer-nigeria`, `coralpay`, `mtn-momo-nigeria`, `opay-nigeria`, `palmpay-nigeria`, `card-nigeria` | `—` | `—` |
| Rwanda | `RWF` | `airtel-rwanda`, `mtn-momo-rwanda` | `—` | `—` |
| Seychelles | `SCR` | `airtel-seychelles` | `—` | `—` |
| Sierra Leone | `SLE` | `orange-sierra-leone` | `—` | `—` |
| Senegal | `XOF` | `mixx-senegal`, `orange-senegal`, `wave-senegal` | `—` | `—` |
| South Sudan | `SSP` | `mtn-momo-south-sudan` | `—` | `—` |
| Eswatini | `SZL` | `mtn-momo-eswatini` | `—` | `—` |
| Chad | `XAF` | `airtel-chad` | `—` | `—` |
| Togo | `XOF` | `mixx-togo`, `moov-togo` | `—` | `—` |
| Tanzania | `TZS` | `airtel-tanzania`, `halopesa-tanzania`, `mpesa-tanzania`, `mixx-tanzania` | `—` | `—` |
| Uganda | `UGX` | `airtel-uganda`, `mtn-momo-uganda` | `—` | `—` |
| South Africa | `ZAR` | `eft-south-africa`, `mtn-momo-south-africa` | `—` | `—` |
| Zambia | `ZMW` | `airtel-zambia`, `mtn-momo-zambia`, `zamtel-zambia` | `—` | `—` |
## Column Guide
Human-readable provider name such as MTN MoMo, Orange, Wave, Bank Transfer, or M-Pesa.
Machine-readable provider identifier used in API calls, for example `mtn-momo-ghana`.
The transaction currency expected for that country and provider row.
* `Collection`: collection or charge flow only
* `Disbursement`: payout or transfer flow only
* `Collection, Disbursement`: the same slug supports both flows
Every provider row currently listed on this page uses `Collection, Disbursement`.
Indicates whether collections use direct processing such as `USSD/STK_PUSH`, redirect, or both.
`Yes` means you may need to call a provider-properties endpoint before initiating a request.
Collection and disbursement limits are shown in separate columns so each provider slug only appears once. Amount values follow the currency minor-unit rules in [Amount Specification](/en/guides/introductions/amount-specification).
Provider availability can change by market, compliance policy, or partner uptime. Confirm your current dashboard setup before going live.
## Detailed Coverage
Jump to: [Angola](#angola) | [Burkina Faso](#burkina-faso) | [Benin](#benin) | [DR Congo](#dr-congo) | [Congo](#congo) | [Ivory Coast](#ivory-coast) | [Cameroon](#cameroon) | [Gabon](#gabon) | [Ghana](#ghana) | [Gambia](#gambia) | [Guinea](#guinea) | [Kenya](#kenya) | [Liberia](#liberia) | [Lesotho](#lesotho) | [Madagascar](#madagascar) | [Mali](#mali) | [Mozambique](#mozambique) | [Namibia](#namibia) | [Niger](#niger) | [Nigeria](#nigeria) | [Rwanda](#rwanda) | [Seychelles](#seychelles) | [Sierra Leone](#sierra-leone) | [Senegal](#senegal) | [South Sudan](#south-sudan) | [Eswatini](#eswatini) | [Chad](#chad) | [Togo](#togo) | [Tanzania](#tanzania) | [Uganda](#uganda) | [South Africa](#south-africa) | [Zambia](#zambia)
Hover a market heading to copy a direct link to that section.
### Angola
3 provider slugs are available. All 3 support collection and disbursement. Currency: `AOA`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------------- | :------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Bank Transfer | bank-transfer-angola | AOA | Collection | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Multicaixa Express | multicaixa-angola | AOA | Collection | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| PayPay | paypay-angola | AOA | Collection, Disbursement | redirect | No | — | — | — | — |
### Burkina Faso
2 provider slugs are available. Both support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------------ | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Moov | moov-burkina-faso | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Orange | orange-burkina-faso | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | 100 | 1,000,000 |
### Benin
2 provider slugs are available. Both support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-benin | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 100 | 3,000,000 | — | — |
| Moov | moov-benin | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 100 | 3,000,000 | — | — |
### DR Congo
4 provider slugs are available. All 4 support collection and disbursement. Currency: `CDF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :----------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| AfriMoney | afrimoney-dr-congo | CDF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Airtel | airtel-dr-congo | CDF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MPesa | mpesa-dr-congo | CDF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Orange | orange-dr-congo | CDF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Congo
2 provider slugs are available. Both support collection and disbursement. Currency: `XAF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-congo | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-congo | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Ivory Coast
4 provider slugs are available. All 4 support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-ivory-coast | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Moov | moov-ivory-coast | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | 500 | 2,000,000 |
| Orange | orange-ivory-coast | XOF | Collection, Disbursement | redirect/processing | No | — | — | 200 | 1,500,000 |
| Wave | wave-ivory-coast | XOF | Collection, Disbursement | redirect | No | — | — | — | — |
### Cameroon
2 provider slugs are available. Both support collection and disbursement. Currency: `XAF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-cameroon | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 500 | 500,000 | 500 | 500,000 |
| Orange | orange-cameroon | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 500 | 500,000 | 500 | 500,000 |
### Gabon
1 provider slug is available. It supports collection and disbursement. Currency: `XAF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :----------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-gabon | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Ghana
3 provider slugs are available. All 3 support collection and disbursement. Currency: `GHS`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| AT | airtel-ghana | GHS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-ghana | GHS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Telecel | telecel-ghana | GHS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Gambia
3 provider slugs are available. All 3 support collection and disbursement. Currency: `GMD`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :--------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| AfriMoney | afrimoney-gambia | GMD | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Airtel | airtel-gambia | GMD | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Wave | wave-gambia | GMD | Collection, Disbursement | redirect | No | — | — | — | — |
### Guinea
2 provider slugs are available. Both support collection and disbursement. Currency: `GNF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-guinea-conakry | GNF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Orange | orange-guinea-conakry | GNF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Kenya
2 provider slugs are available. Both support collection and disbursement. Currency: `KES`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :-------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-kenya | KES | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| M-Pesa | safaricom-kenya | KES | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Liberia
1 provider slug is available. It supports collection and disbursement. Currency: `LRD`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :--------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-liberia | LRD | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Lesotho
1 provider slug is available. It supports collection and disbursement. Currency: `LSL`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :--------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-lesotho | LSL | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Madagascar
1 provider slug is available. It supports collection and disbursement. Currency: `MGA`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-madagascar | MGA | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Mali
2 provider slugs are available. Both support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Moov | moov-mali | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Orange | orange-mali | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Mozambique
2 provider slugs are available. Both support collection and disbursement. Currency: `MZN`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :------------- | :--------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Movitel e-Mola | emola-mozambique | MZN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Vodacom M-Pesa | mpesa-mozambique | MZN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Namibia
1 provider slug is available. It supports collection and disbursement. Currency: `NAD`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :--------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-namibia | NAD | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Niger
1 provider slug is available. It supports collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :----------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-niger | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Nigeria
7 provider slugs are available. All 7 support collection and disbursement, and `bank-transfer-nigeria` requires fetch properties. Currency: `NGN`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :------------ | :-------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-smartcash-ng | NGN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Bank Transfer | bank-transfer-nigeria | NGN | Collection, Disbursement | processing (USSD/STK\_PUSH) | Yes | — | — | — | — |
| CoralPay | coralpay | NGN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-nigeria | NGN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Opay | opay-nigeria | NGN | Collection, Disbursement | redirect | No | — | — | — | — |
| PalmPay | palmpay-nigeria | NGN | Collection, Disbursement | redirect | No | — | — | — | — |
| card-nigeria | card-nigeria | NGN | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Rwanda
2 provider slugs are available. Both support collection and disbursement. Currency: `RWF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :-------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-rwanda | RWF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-rwanda | RWF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Seychelles
1 provider slug is available. It supports collection and disbursement. Currency: `SCR`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-seychelles | SCR | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Sierra Leone
1 provider slug is available. It supports collection and disbursement. Currency: `SLE`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------------ | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Orange | orange-sierra-leone | SLE | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Senegal
3 provider slugs are available. All 3 support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Mixx by Yas | mixx-senegal | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Orange | orange-senegal | XOF | Collection, Disbursement | redirect | No | — | — | — | — |
| Wave | wave-senegal | XOF | Collection, Disbursement | redirect | No | — | — | — | — |
### South Sudan
1 provider slug is available. It supports collection and disbursement. Currency: `SSP`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-south-sudan | SSP | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Eswatini
1 provider slug is available. It supports collection and disbursement. Currency: `SZL`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| MTN MoMo | mtn-momo-eswatini | SZL | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Chad
1 provider slug is available. It supports collection and disbursement. Currency: `XAF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-chad | XAF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Togo
2 provider slugs are available. Both support collection and disbursement. Currency: `XOF`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :-------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Mixx by Yas | mixx-togo | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Moov | moov-togo | XOF | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Tanzania
4 provider slugs are available. All 4 support collection and disbursement. Currency: `TZS`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :---------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-tanzania | TZS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 100 | — | 1,000 | — |
| Halopesa | halopesa-tanzania | TZS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 100 | — | 100 | — |
| MPesa | mpesa-tanzania | TZS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | 100 | — | 200 | — |
| Mixx by Yas | mixx-tanzania | TZS | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Uganda
2 provider slugs are available. Both support collection and disbursement. Currency: `UGX`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :-------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-uganda | UGX | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-uganda | UGX | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### South Africa
2 provider slugs are available. Both support collection and disbursement. Currency: `ZAR`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------------------------- | :-------------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Electronic Fund Transfer (EFT) | eft-south-africa | ZAR | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-south-africa | ZAR | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
### Zambia
3 provider slugs are available. All 3 support collection and disbursement. Currency: `ZMW`.
| **Provider** | **Slug** | **Currency** | **Supported Flows** | **Collection Processing Type** | **Fetch Properties** | **Collection Min** | **Collection Max** | **Disbursement Min** | **Disbursement Max** |
| :----------- | :-------------- | :----------- | :----------------------- | :----------------------------- | :------------------- | :----------------- | :----------------- | :------------------- | :------------------- |
| Airtel | airtel-zambia | ZMW | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| MTN MoMo | mtn-momo-zambia | ZMW | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
| Zamtel | zamtel-zambia | ZMW | Collection, Disbursement | processing (USSD/STK\_PUSH) | No | — | — | — | — |
## Related Docs
Integration options for checkout and direct charge flows.
Step-by-step guidance for payout and transfer workflows.
Endpoint details, request schemas, and response models.
# Testing
Source: https://docs.payfonte.com/en/guides/introductions/testing
Sandbox testing guide for Payfonte integrations, including provider simulators, webhook validation, and test scenarios.
Use sandbox first for all integration validation before moving to production.
## Sandbox Setup
API base URL: `https://sandbox-api.payfonte.com`
Get your `client-id` and `client-secret` from `Settings -> Security -> API Keys and Webhooks` in [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com).
Configure a test callback URL so you can validate async transaction updates.
## What To Validate Before Go-Live
Confirm all requests include `client-id` and `client-secret`.
Confirm you send integer minor-unit values only. Decimals are not supported.
Validate pending/processing to final states (`success` or `failed`) in your
business flow.
Verify signature validation, retries, idempotency, and response timing.
## Core Test Scenarios
| Scenario | Expected Result |
| --------------------- | ------------------------------------------------- |
| Valid charge request | `201` response with transaction reference |
| Invalid credentials | Authentication failure (`401`/`403`) |
| Decimal amount sent | Validation/provider failure |
| Duplicate reference | `409` with `DuplicateTransactionReference` |
| Invalid provider slug | Error with `InvalidProvider` |
| Webhook delivery | Callback received and processed once (idempotent) |
## Simulate Success, Failed, and Pending Outcomes
For both collections and disbursements in sandbox, you can control the expected transaction outcome by changing the mobile money phone number used in the request.
| Phone Number Pattern | Expected Result | How To Use It |
| ------------------------- | --------------- | -------------------------------------------------------------------- |
| Any other phone number | `success` | Sandbox treats all other phone numbers as successful transactions |
| Number ending in `000000` | `failed` | Sandbox forces the transaction to fail |
| Number ending in `111111` | `pending` | Sandbox keeps the transaction pending so you can test async handling |
Apply this rule to the phone number field you send for the transaction. For
collections, use the customer's mobile money number. For disbursements, use
the recipient phone number.
When testing pending flows, do not treat the initial API response as final. Wait for webhook updates or verify the transaction status from your backend before marking the transaction as `success` or `failed`.
## Card Test Details
Use these sandbox card details to test card collection authentication paths and final outcomes.
| Test Scenario | Number | Expiry | CVV | PIN | OTP |
| -------------------- | ------------------------------ | ------- | ----- | ------ | -------- |
| Pin - PENDING | `5061 4604 1012 1111 101` | `12/50` | `557` | `1102` | `543210` |
| Pin+OTP - PENDING | `5061 4604 1012 1111 102` | `12/50` | `558` | `1103` | `543210` |
| Pin+3DS - PENDING | `5061 4604 1012 1111 103` | `12/50` | `559` | `1107` | `543210` |
| Pin - SUCCESS | `5061 4604 1012 1111 104` | `12/50` | `560` | `1104` | `543210` |
| Pin+OTP - SUCCESS | `5061 4604 1012 1111 105` | `12/50` | `561` | `1105` | `543210` |
| Pin+3DS - SUCCESS | `5061 4604 1012 1111 106` | `12/50` | `562` | `1106` | `543210` |
| Pin - FAIL | `5061 4604 1012 1111 107` | `12/50` | `563` | `1107` | `123456` |
| Pin+OTP - FAIL | `5061 4604 1012 1111 108` | `12/50` | `564` | `1108` | `245678` |
| Pin+3ds - FAIL | `5061 4604 1012 1111 109` | `12/50` | `565` | `1109` | `456789` |
| No auth | `5061 4604 1012 1111 110` | `12/50` | `566` | `1110` | `234567` |
| Insufficient balance | `5061 4604 1012 1111 111` | `12/50` | `567` | `1111` | `334455` |
| Expired card | `5061 4604 1012 1111 112` | `3/50` | `568` | `1111` | `334455` |
| 3DS - SUCCESS | `4508 7500 15741 019(USD)` | `12/50` | `100` | | |
| 3DS - SUCCESS | `4012 0000 3333 0026(USD)` | `12/50` | `100` | | |
| 3DS - SUCCESS | `5123 4500 0000 0008(USD)` | `12/50` | `100` | | |
| 3DS - FAIL | `2223 0000 0000 0007(USD)` | `12/50` | `100` | | |
| 3DS - FAIL | `5111 1111 1111 1118(USD)` | `12/50` | `100` | | |
| 3DS - FAIL | `2223 0000 0000 0007(USD)` | `12/50` | `100` | | |
| 3DS - PENDING | `5061 4604 1012 1111 103(USD)` | `12/50` | `100` | `1107` | |
## Provider-Specific Test Data
For Orange Ivory Coast testing on Payfonte:
1. Open [https://mpayment.orange-money.com/mpayment-otp/login](https://mpayment.orange-money.com/mpayment-otp/login)
2. Sign in with:
* Username: `7701901040`
* Password: `MerchantWP01040`
3. Generate OTP with:
* Phone Number: `7701101040` (usually pre-loaded)
* PIN: `1791`
4. Use the generated OTP on the payment platform.
* Success example: `254700123456`
* Failed example: `254700000000`
* Pending example: `254711111111`
* Success example: `233242426222`
* Failed example: `233240000000`
* Pending example: `233241111111`
## Quick Sandbox Request
```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
--header 'client-id: ' \
--header 'client-secret: ' \
--header 'Content-Type: application/json' \
--data '{
"reference": "test-001",
"amount": 10000,
"currency": "NGN",
"country": "NG",
"user": {
"phoneNumber": "08012345678"
}
}'
```
## Related Docs
Sandbox and production URLs and credential setup.
Verify callback payloads and signature handling.
Troubleshoot failed test requests quickly.
# Wallets
Source: https://docs.payfonte.com/en/guides/introductions/wallets
Understand Payfonte wallet types, balances, and operational actions for collections and disbursements.
Payfonte assigns wallets per merchant and market to separate collection inflows from disbursement outflows.
## Wallet Types
Incoming payment funds are settled here first. Use this wallet as your primary collection balance.
Disbursement and transfers are deducted from this wallet when you run disbursements.
## Wallet Status
Wallets can appear in these states:
| Status | Meaning |
| --------------- | ----------------------------------------------------------------- |
| `active` | Wallet can receive and send funds based on configured operations. |
| `post-no-debit` | Wallet can receive funds, but outgoing debits are blocked. |
`post-no-debit` is commonly used as a safety control when credentials or disbursement controls may be compromised.
## Wallet Operations
Move funds from collection wallet to disbursement wallet when you need disbursement liquidity.
Apply a suspend/post-no-debit control to stop outgoing deductions while investigations or security checks are ongoing.
Remove restrictions when controls are restored and your account is verified as safe.
## Fetch Wallet Balances via API
Use the wallet endpoint to query current balances by `country` and `currency`.
```bash theme={null}
curl --location 'https://api.payfonte.com/billing/v1/wallets?country=NG¤cy=NGN' \
--header 'client-id: ' \
--header 'client-secret: '
```
Sample response shape:
```json theme={null}
{
"data": [
{
"type": "deposit",
"amount": 1250000,
"currency": "NGN",
"country": "NG",
"status": "active"
},
{
"type": "disbursement",
"amount": 500000,
"currency": "NGN",
"country": "NG",
"status": "active"
}
]
}
```
## Recommended Workflow
Track funds entering your deposit/collection wallet after successful transactions.
Transfer enough balance to disbursement wallet before high-volume disbursement runs.
Set internal alerts so disbursement operations do not fail due to insufficient wallet funds.
If compromise is suspected, suspend outgoing wallet operations and rotate credentials immediately.
## Related Docs
Secure wallet API calls with required headers.
Learn disbursement flows that use your disbursement wallet.
Full endpoint details for wallet queries.