Process alternative payment
Initiate the alternative payment flow with a specific processor selected from the list returned at creation time. The response shape depends on the processor β Migo normalizes it through a data.type discriminator so the merchant frontend can render the right UI.
POST https://mw.migopayments.com/api/v1/integrations/transactions/{transactionId}/payments
See the live spec entry: POST /api/v1/integrations/transactions/{transactionId}/payments.
Auth recap. Every call sends
Authorization: Bearer <token>. See Authentication for details.
Request β unified bodyβ
The body is the same shape for every processor. The integrator may always send every documented field; the runtime only reads the keys that apply to the chosen processor. Fields that do not apply are ignored.
{
"processor": "bamPaymentButton",
"data": {
"user": "",
"phoneNumber": "",
"installments": 1
}
}
| Field | Type | Required | Notes |
|---|---|---|---|
processor | string | yes | Must be present in the paymentMethods array returned at creation time. |
data | object | yes (may be {}) | Unified envelope β see field-to-processor mapping below. The runtime only reads the keys that apply to the chosen processor; everything else is ignored. |
Field-to-processor mappingβ
The integrator can stay on a single body shape and only fill what applies. Send empty strings, {}, or omit fields β Migo ignores everything outside the active processor's documented payload.
Field in data | Used by |
|---|---|
user or phoneNumber (at least one) | fri |
installments | bamPaymentButton |
Processors with no data requirement (send data: {} or omit unused keys): bancoIndustrial, quickPayQR, akisiQR, pronet, zigi.
The full unified shape is documented in the spec as AlternativePaymentDataDto.
cURL β BAM Payment Button (Guatemala)β
curl -X POST https://mw.migopayments.com/api/v1/integrations/transactions/trx_8f3c2b1d9e7a/payments \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"processor": "bamPaymentButton",
"data": { "installments": 1 }
}'
Node.jsβ
const res = await fetch(
`https://mw.migopayments.com/api/v1/integrations/transactions/${transactionId}/payments`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MIGO_JWT}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
processor: 'bamPaymentButton',
data: { installments: 1 },
}),
}
);
const { data } = await res.json();
// data.type drives the rendering branch
if (data.type === 'url') window.location.href = data.data; // Zigi, BAM Payment Button
if (data.type === 'base64') renderImage(data.data); // Akisi QR, Banco Industrial
if (data.type === 'json') renderStructuredPayload(data.data); // Pronet, QuickPay QR, FRI
Per-processor request examplesβ
Every example uses the same unified body shape. The integrator may keep the same client-side type and only populate the fields that apply β Migo ignores keys outside the active processor's payload.
FRI (push payment)β
fri requires at least one of user or phoneNumber.
{
"processor": "fri",
"data": {
"user": "fri-user-001"
}
}
BAM Payment Button (Guatemala, hosted redirect)β
{
"processor": "bamPaymentButton",
"data": {
"installments": 1
}
}
Processors with no data (send {})β
bancoIndustrial, quickPayQR, akisiQR, pronet, zigi β the customer pays via their app after Migo issues the QR / push notification.
{
"processor": "bancoIndustrial",
"data": {}
}
Response shape by data.typeβ
data.type | Render strategy | Payload field | Example processors |
|---|---|---|---|
url | Redirect customer to URL | data.data is the URL string | Zigi, BAM Payment Button |
qr | Render QR image from a raw EMVCo string | data.data is the QR string | (none currently) |
base64 | Drop the value into <img src=...> directly | data.data is a data:image/png;base64,β¦ URI | Akisi QR, Banco Industrial |
json | Structured payload (references) | data.data is the structured payload | Pronet, QuickPay QR, FRI |
data.data, not data.valueThe runtime emits the payload under data.data. Earlier recipes (notably recipes/guatemala.md) used data.value β that variant is outdated. When parsing the response, always read data.data.
Sample for type: "url":
{
"success": true,
"message": "success",
"data": {
"uid": "trx_8f3c2b1d9e7a",
"type": "url",
"data": "https://gateway.example.com/redirect/abc",
"cancelAt": 600
}
}
Sample for type: "base64" (Akisi QR β verified against sb-mw.migopayments.com):
{
"success": true,
"message": "Success",
"data": {
"transaction_id": "12740927961946781727",
"type": "base64",
"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJQAAAβ¦"
}
}
The transaction identifier in the response comes back as uid for some rails (e.g. Zigi, BAM Payment Button) and as transaction_id for others (e.g. Akisi QR, QuickPay QR). The two fields you must always read to render are type and data.
Polling vs webhooksβ
Migo confirms the final status through your processor webhook (APPROVED, DENIED, EXPIRED). For UX you can poll the transaction status every 3β5 seconds while the customer completes the rail; do not rely on polling for state-of-record β the webhook is authoritative.
Errorsβ
| HTTP | Cause |
|---|---|
| 400 | Missing parameters, processor not allowed for this client, or required data keys missing (response includes data.missingValues) |
| 401 | User-side authentication failed (Ridivi) |
| 405 | Processor temporarily unavailable (e.g. Banco Industrial returns an unavailabilityReason) |
| 500 | Processor request could not be processed |