Collections
Collections allow you to receive payments from customers via mobile money. This section covers everything you need to know about collecting payments through ZoPay.
Overview
The collection process involves three main steps:
- Create a Quote: Get pricing information for the transaction
- Execute Collection: Process the payment from the customer
- Check Status: Monitor the transaction status
Supported Gateways
- MTN Mobile Money: Available in Cameroon, Ivory Coast, and other supported countries
- Orange Money: Merchant payment integration
Collection Flow
- Customer initiates payment on your platform
- Your application creates a quote via
POST /api/v1/wallets/quote - Quote includes fees and total amount
- Customer confirms payment details
- Your application executes collection via
POST /api/v1/wallets/collect - ZoPay processes payment with the mobile money provider
- Webhook notification sent when transaction completes
- Check transaction status via
GET /api/v1/wallets/transactions/:id
Transaction Statuses
- PENDING: Transaction initiated, awaiting processing
- VERIFYING: Payment is being verified with the gateway
- SUCCESS: Payment completed successfully
- FAILED: Payment failed (check error details)
- CANCELLED: Transaction was cancelled
Fees
Each collection includes:
- Gateway Fee: Fee charged by the mobile money provider (MTN, Orange, etc.)
- Platform Fee: ZoPay service fee
- Total Amount: Amount customer pays (original amount + fees)
- Net to Merchant: Amount you receive after fees
Idempotency
Always include an idempotency_key when executing collections. This ensures that if a request is retried due to network issues, the same transaction won't be processed twice.
Create Quote
Before executing a collection, you should create a quote to get pricing information including fees and the total amount the customer will pay.
Endpoint
1POST /api/v1/wallets/quoteNote: This endpoint is used for both collections and disbursements. Set transaction_type to COLLECTION or DISBURSEMENT.
Request Body
1{
2 "gateway": "MTN_MOMO",
3 "transaction_type": "COLLECTION",
4 "amount": "10000",
5 "currency": "XAF",
6 "payer": {
7 "msisdn": "+237612345678"
8 }
9}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
gateway | string | Yes | Payment gateway (e.g., "MTN_MOMO", "ORANGE_MONEY") |
transaction_type | string | Yes | Type of transaction: "COLLECTION" or "DISBURSEMENT" |
amount | string | Yes | Transaction amount as a string |
currency | string | Yes | Currency code (e.g., "XAF", "USD") |
payer.msisdn | string | Yes | Customer phone number in E.164 format |
Response
1{
2 "quote_id": "quote-uuid",
3 "fees": {
4 "gateway_fee": "50.00",
5 "platform_fee": "100.00"
6 },
7 "total_amount": "10150.00",
8 "net_to_merchant": "10150.00",
9 "expires_at": "2024-01-15T10:45:00.000Z"
10}Response Fields
| Field | Type | Description |
|---|---|---|
quote_id | string | Unique quote identifier (use this in execute collection) |
fees.gateway_fee | string | Fee charged by the mobile money provider |
fees.platform_fee | string | ZoPay platform fee |
total_amount | string | Total amount customer will pay (amount + fees) |
net_to_merchant | string | Amount you will receive after fees |
expires_at | string | Quote expiration timestamp (ISO 8601) |
Example Request
1const response = await fetch('https://api.zopay.com/api/v1/wallets/quote', {
2 method: 'POST',
3 headers: {
4 'Content-Type': 'application/json',
5 'x-zo-key': 'your-api-key',
6 'x-zo-timestamp': Math.floor(Date.now() / 1000).toString(),
7 'x-zo-nonce': crypto.randomBytes(16).toString('hex'),
8 'x-zo-origin': 'https://yourdomain.com',
9 'x-zo-signature': signature,
10 'x-zo-version': '1.0'
11 },
12 body: JSON.stringify({
13 gateway: 'MTN_MOMO',
14 transaction_type: 'COLLECTION',
15 amount: '10000',
16 currency: 'XAF',
17 payer: {
18 msisdn: '+237612345678'
19 }
20 })
21});
22
23const quote = await response.json();Execute Collection
After creating a quote, use this endpoint to process the actual payment from the customer.
Endpoint
1POST /api/v1/wallets/collectRequest Body
1{
2 "quote_id": "quote-uuid",
3 "idempotency_key": "unique-payment-123"
4}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
quote_id | string | Yes | Quote ID from the create quote response |
idempotency_key | string | Yes | Unique identifier to prevent duplicate transactions |
Response
1{
2 "transaction_id": "txn-uuid",
3 "status": "VERIFYING",
4 "gateway_reference": "MTN_REF_123456789",
5 "correlation_id": "corr-uuid"
6}Response Fields
| Field | Type | Description |
|---|---|---|
transaction_id | string | Unique transaction identifier |
status | string | Initial transaction status (usually "VERIFYING") |
gateway_reference | string | Reference from the mobile money provider |
correlation_id | string | Correlation ID for tracking |
Example Request
1const response = await fetch('https://api.zopay.com/api/v1/wallets/collect', {
2 method: 'POST',
3 headers: {
4 'Content-Type': 'application/json',
5 'x-zo-key': 'your-api-key',
6 'x-zo-timestamp': Math.floor(Date.now() / 1000).toString(),
7 'x-zo-nonce': crypto.randomBytes(16).toString('hex'),
8 'x-zo-origin': 'https://yourdomain.com',
9 'x-zo-signature': signature,
10 'x-zo-version': '1.0'
11 },
12 body: JSON.stringify({
13 quote_id: 'quote-uuid',
14 idempotency_key: 'unique-payment-123'
15 })
16});
17
18const transaction = await response.json();Transaction Status
Check the status of a collection transaction to see if it has been completed, failed, or is still processing.
Endpoint
1GET /api/v1/wallets/transactions/:idPath Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Transaction ID from the execute collection response |
Response
1{
2 "transaction": {
3 "id": "txn-uuid",
4 "merchantId": "merchant-uuid",
5 "gateway": "MTN_MOMO",
6 "amount": "10000.00",
7 "currency": "XAF",
8 "status": "SUCCESS",
9 "gatewayReference": "MTN_REF_123456789",
10 "gatewayFee": "50.00",
11 "platformFee": "100.00",
12 "createdAt": "2024-01-15T10:00:00.000Z",
13 "completedAt": "2024-01-15T10:01:00.000Z"
14 }
15}Response Fields
| Field | Type | Description |
|---|---|---|
transaction.id | string | Unique transaction identifier |
transaction.merchantId | string | Merchant identifier |
transaction.gateway | string | Payment gateway used |
transaction.amount | string | Transaction amount |
transaction.currency | string | Currency code |
transaction.status | string | Transaction status (PENDING, VERIFYING, SUCCESS, FAILED, CANCELLED) |
transaction.gatewayReference | string | Reference from the mobile money provider |
transaction.gatewayFee | string | Fee charged by the gateway |
transaction.platformFee | string | ZoPay platform fee |
transaction.createdAt | string | Transaction creation timestamp |
transaction.completedAt | string | Transaction completion timestamp (null if not completed) |
Example Request
1const response = await fetch('https://api.zopay.com/api/v1/wallets/transactions/txn-uuid', {
2 method: 'GET',
3 headers: {
4 'x-zo-key': 'your-api-key',
5 'x-zo-timestamp': Math.floor(Date.now() / 1000).toString(),
6 'x-zo-nonce': crypto.randomBytes(16).toString('hex'),
7 'x-zo-origin': 'https://yourdomain.com',
8 'x-zo-signature': signature,
9 'x-zo-version': '1.0'
10 }
11});
12
13const transaction = await response.json();Status Polling
After executing a collection, you should poll this endpoint periodically to check the transaction status. Alternatively, you can set up webhooks to receive real-time notifications when the transaction status changes.