Skip to main content
Migo Docs

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
}
}
FieldTypeRequiredNotes
processorstringyesMust be present in the paymentMethods array returned at creation time.
dataobjectyes (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 dataUsed by
user or phoneNumber (at least one)fri
installmentsbamPaymentButton

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.typeRender strategyPayload fieldExample processors
urlRedirect customer to URLdata.data is the URL stringZigi, BAM Payment Button
qrRender QR image from a raw EMVCo stringdata.data is the QR string(none currently)
base64Drop the value into <img src=...> directlydata.data is a data:image/png;base64,… URIAkisi QR, Banco Industrial
jsonStructured payload (references)data.data is the structured payloadPronet, QuickPay QR, FRI
Field name is data.data, not data.value

The 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 identifier field varies by rail

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​

HTTPCause
400Missing parameters, processor not allowed for this client, or required data keys missing (response includes data.missingValues)
401User-side authentication failed (Ridivi)
405Processor temporarily unavailable (e.g. Banco Industrial returns an unavailabilityReason)
500Processor request could not be processed