Collections
Request payments from your customers and get paid into your wallet.
/collectionsCreate a collectionGET/collections/{id}Retrieve a collectionGET/collectionsList collectionsGET/collections/requirementsMethods and fieldsPOST/collections/{id}/mock-settleSettle in SandboxA collection is a payment request for a set amount. MigraPay returns payment instructions (account details or an Interac e-Transfer destination) plus a hosted checkout link you can send to your customer. When the customer pays, the amount less fees is credited to your wallet in that currency and a collection.settled webhook fires.
To choose between collections, checkouts and payment links, see the Collections guide.
Create a collection
POST /collections requires the collection.create scope and supports Idempotency-Key.
Prop
Type
curl -X POST https://business-api.migrapay.com/v1/api/collections \
-H "Authorization: Bearer $MIGRAPAY_API_KEY" \
-H "Idempotency-Key: 4f1c2b8e-9d3a-4e7f-8b21-6a5c0d9e7f13" \
-H "Content-Type: application/json" \
-d '{
"currency": "NGN",
"amount": 25000,
"rail": "dynamic_virtual_account",
"reference": "INV-2048",
"description": "Invoice 2048",
"expiresInMinutes": 60
}'{
"status": "success",
"message": "Payment request created successfully.",
"data": {
"id": "6b3e8f1a-2d4c-4e9b-8a7f-000000000001",
"status": "awaiting_payment",
"currency": "NGN",
"amount": 25000,
"rail": "dynamic_virtual_account",
"instruction": {
"method": "virtual_account",
"details": {
"accountNumber": "9912345678",
"bankName": "Example Bank",
"accountName": "Acme Ltd Checkout",
"expiresAt": "2026-08-12T18:15:00.000Z"
},
"reference": "MPC-7KD2QX9A"
},
"publicToken": "pr_9Fh2kLm7Qx3Vb8Ns",
"checkoutUrl": "https://pay.migrapay.com/pay/pr_9Fh2kLm7Qx3Vb8Ns"
}
}| Field | Description |
|---|---|
instruction | How the customer pays. method is virtual_account or interac; details holds what to show them; reference is the payment reference the customer should quote, where the method uses one. |
checkoutUrl | A hosted page with the same instructions. Send it to your customer instead of building your own screen. |
publicToken | The token in checkoutUrl. |
The fields in instruction.details depend on the method:
- Account details (
virtual_account):accountNumber,bankName,accountNameand, for one-time accounts,expiresAt. Some methods return apaymentUrlinstead ofaccountName. - Interac (
interac):depositMailbox(the email address to send the e-Transfer to),sendAmount,currency,reference(the payment code for this request, the same value asinstruction.reference) andinstructions, a sentence you can show the payer as is. See Interac e-Transfer.
{
"method": "interac",
"details": {
"depositMailbox": "[email protected]",
"sendAmount": 250,
"currency": "CAD",
"reference": "ACME7K-1001",
"instructions": "Send exactly 250.00 CAD by Interac e-Transfer to [email protected] and put ACME7K-1001 in the message."
},
"reference": "ACME7K-1001"
}Errors: 400 VALIDATION_ERROR, 404 SUB_MERCHANT_NOT_FOUND, 422 SUB_MERCHANT_INACTIVE, 422 BUSINESS_NOT_ACTIVE, 422 UNSUPPORTED_PAYIN_RAIL (collections are not available in that currency).
Retrieve a collection
GET /collections/{id} requires collection.view.
curl https://business-api.migrapay.com/v1/api/collections/6b3e8f1a-2d4c-4e9b-8a7f-000000000001 \
-H "Authorization: Bearer $MIGRAPAY_API_KEY"{
"status": "success",
"message": "Payment request retrieved successfully.",
"data": {
"id": "6b3e8f1a-2d4c-4e9b-8a7f-000000000001",
"subMerchantId": null,
"currency": "NGN",
"amount": 25000,
"rail": "dynamic_virtual_account",
"status": "settled",
"reference": "INV-2048",
"description": "Invoice 2048",
"customerName": "Chidi Eze",
"createdAt": "2026-08-12T17:15:00.000Z",
"grossAmount": 25000,
"fee": 250,
"net": 24750,
"payer": { "name": "Chidi Eze", "email": null, "phone": null },
"paymentCode": null,
"source": {
"sourceAccount": { "name": "CHIDI EZE", "bank": "Example Bank", "accountNumberMasked": "******4821" }
},
"settledAt": "2026-08-12T17:21:40.000Z",
"refundedTotal": 0,
"refundable": 25000
}
}| Field | Description |
|---|---|
paymentCode | Interac only: the code the payer was asked to put in the e-Transfer message. null for other rails. |
payer | Who the collection was requested from: name, email and phone, as given when it was created. |
source | What arrived with the money, once paid. Interac: senderName, senderEmail, interacReference (the e-Transfer's own reference number) and message. NGN account transfers: sourceAccount with name, bank and accountNumberMasked. null before payment. |
Unknown ids return 404 REQUEST_NOT_FOUND. To find the wallet credit for a settled collection, search transactions with activity=collection; its paymentRequestId is the collection id.
List collections
GET /collections returns your collections newest first, paginated. Requires collection.view.
Prop
Type
{
"status": "success",
"message": "Payment requests retrieved successfully.",
"data": {
"requests": [
{
"id": "6b3e8f1a-2d4c-4e9b-8a7f-000000000001",
"currency": "NGN",
"amount": 25000,
"rail": "dynamic_virtual_account",
"status": "settled",
"customerName": "Chidi Eze",
"createdAt": "2026-08-12T17:15:00.000Z",
"reference": "INV-2048",
"publicToken": "pr_9Fh2kLm7Qx3Vb8Ns"
}
],
"total": 1,
"page": 1,
"pageSize": 100,
"totalPages": 1
}
}data.items carries the same list as data.requests.
Collection requirements
GET /collections/requirements lists, per currency and country, which collection methods you can request and the body fields each one takes. Requires collection.view.
Prop
Type
curl "https://business-api.migrapay.com/v1/api/collections/requirements?currency=CAD&method=interac" \
-H "Authorization: Bearer $MIGRAPAY_API_KEY"{
"status": "success",
"message": "Collection requirements retrieved successfully.",
"data": {
"corridors": [
{
"currency": "CAD",
"country": "Canada",
"countryCode": "CA",
"limits": { "min": 1, "max": null },
"available": true,
"rails": [
{
"key": "interac",
"label": "Interac e-Transfer",
"available": true,
"notes": "Interac e-Transfer in Canadian dollars. The response tells the payer where to send the transfer and the code to include.",
"fields": [
{ "name": "reference", "label": "Reference", "type": "string", "required": false, "example": "INV-1042", "helpText": "Your own reference for this collection." },
{ "name": "description", "label": "Description", "type": "string", "required": false, "example": "Invoice 1042", "helpText": "What the payment is for." },
{ "name": "customerName", "label": "Payer name", "type": "string", "required": false, "maxLength": 200, "example": "Ada Obi" },
{ "name": "payerEmail", "label": "Payer email", "type": "email", "required": false, "example": "[email protected]", "helpText": "The email the payer sends the e-Transfer from. Used to match the payment to this request." },
{ "name": "payerPhone", "label": "Payer phone", "type": "phone", "required": false, "maxLength": 32, "example": "+2348012345678" },
{ "name": "expiresInMinutes", "label": "Expires in (minutes)", "type": "number", "required": false, "pattern": "^[1-9][0-9]*$", "example": "60", "helpText": "Whole minutes until the request expires. Leave out for no expiry." }
]
}
]
}
]
}
}Each field has name, label, type (string, number, select, phone or email), required, an example, and where relevant pattern, minLength, maxLength and helpText. limits.min is the smallest amount you can request. When a currency or a method is switched off, available is false and reason is CURRENCY_DISABLED or RAIL_DISABLED.
Settle in Sandbox
POST /collections/{id}/mock-settle settles a Sandbox collection as if the customer had paid. Requires collection.create and a Sandbox key; a Live key gets 403 MOCK_REQUIRES_SANDBOX.
The collection moves to settled, its amount less your collection fee is credited to your Sandbox wallet, a collection transaction is recorded, and collection.settled is sent to your webhooks with "mode": "sandbox" and a realistic funding object.
Prop
Type
curl -X POST https://business-api.migrapay.com/v1/api/collections/6b3e8f1a-2d4c-4e9b-8a7f-000000000001/mock-settle \
-H "Authorization: Bearer $MIGRAPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "customerName": "Chidi Eze", "customerEmail": "[email protected]" }'{
"status": "success",
"message": "Collection mock-settled successfully.",
"data": {
"collectionId": "6b3e8f1a-2d4c-4e9b-8a7f-000000000001",
"net": 24750,
"fee": 250
}
}net is what was credited and fee the collection fee. Calling it again on a settled collection returns the same result without crediting twice. Expired, failed or refunded collections return 422 NOT_COLLECTABLE; unknown ids return 404 REQUEST_NOT_FOUND.
Collection lifecycle
- awaiting_paymentInstructions issued; waiting for the customer.
- processingPayment received and being confirmed.
- settledFunds credited to your wallet. collection.settled fires.
- expiredNot paid in time.
- failedThe payment could not be completed.
- refundedReturned to the payer after settling. collection.refunded fires.