Collections

Request payments from your customers and get paid into your wallet.

A 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
  }'
201 Created
{
  "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"
  }
}
FieldDescription
instructionHow 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.
checkoutUrlA hosted page with the same instructions. Send it to your customer instead of building your own screen.
publicTokenThe token in checkoutUrl.

The fields in instruction.details depend on the method:

  • Account details (virtual_account): accountNumber, bankName, accountName and, for one-time accounts, expiresAt. Some methods return a paymentUrl instead of accountName.
  • Interac (interac): depositMailbox (the email address to send the e-Transfer to), sendAmount, currency, reference (the payment code for this request, the same value as instruction.reference) and instructions, a sentence you can show the payer as is. See Interac e-Transfer.
instruction for a CAD Interac collection
{
  "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"
200 OK
{
  "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
  }
}
FieldDescription
paymentCodeInterac only: the code the payer was asked to put in the e-Transfer message. null for other rails.
payerWho the collection was requested from: name, email and phone, as given when it was created.
sourceWhat 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

200 OK
{
  "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"
200 OK
{
  "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]" }'
200 OK
{
  "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

  1. awaiting_paymentInstructions issued; waiting for the customer.
  2. processingPayment received and being confirmed.
  3. settledFunds credited to your wallet. collection.settled fires.
  4. expiredNot paid in time.
  5. failedThe payment could not be completed.
  6. refundedReturned to the payer after settling. collection.refunded fires.