Colombia — integration recipes
The rails wired on the alternative-payments /payments endpoint for Colombia are Nequi (nequi) and GlobalPay PSE (globalPay-PSE).
Setup (do this once)
All recipes assume the variables below. Set them in your shell before running any curl. The host (sb-mw.migopayments.com) and the path (/api/v1/integrations/...) are the public sandbox reachable by external integrators. The Alternative Payments routes accept the long-lived 64-char merchant token as a Bearer token — see Authentication → Header format by endpoint.
export MIGO_BASE="https://sb-mw.migopayments.com"
export MIGO_CLIENT="<your-client-slug>"
export MIGO_TOKEN="<your-64-char-merchant-token>" # 64 hex chars
export MIGO_USER_ID="+57300000000"
export UID=$(
curl -s -X POST "$MIGO_BASE/api/v1/integrations/transactions" \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"amount\": 50000,
\"channel\": \"web\",
\"client\": \"$MIGO_CLIENT\",
\"userId\": \"$MIGO_USER_ID\",
\"customKeys\": { \"orderId\": \"recipe-test\" }
}" | jq -r '.data.uid'
)
Inspect the returned paymentMethods to confirm which rails your client has enabled (resolved at runtime from clientConfig.processors).
Nequi (nequi) — direct
Country: Colombia · Type: Push notification to the customer's Nequi app · Pre-call
payment-intents: Optional (returns phone fixture in sandbox) · Response payload:payButton.
Step A (optional) — Fetch fixture data
curl -X POST "$MIGO_BASE/api/v1/integrations/transactions/$UID/payment-intents" \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "processor": "nequi" }'
The payment-intents handler special-cases nequi; production callers typically collect the phone from the user.
Step B — Process payment
curl -X POST "$MIGO_BASE/api/v1/integrations/transactions/$UID/payments" \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "processor": "nequi", "data": { "phoneNumber": "3001234567" } }'
Expected response — data.data carries the Nequi paymentRequest.message:
{
"success": true,
"message": "Success",
"data": {
"transaction_id": "…",
"type": "payButton",
"data": "<paymentRequest.message>",
"cancelAt": null
}
}
payButton means the customer is authorizing inside their Nequi app. There is no public GET-by-uid endpoint on this surface to poll — rely on the merchant callback configured in clientConfig.callback for status (see Merchant Generic Callback).
Refunds: nequi revert via POST $MIGO_BASE/revert with body {"transactionUid":"$UID","processor":"nequi"} (JWT-Bearer scheme, separate from this merchant-token surface).
Done checklist
-
paymentMethodscontainednequi. -
payButtonresponse read fromdata.data. - Merchant callback received for the test phone.
GlobalPay PSE (globalPay-PSE)
Country: Colombia · Type: PSE — customer is redirected to their bank's online portal · Pre-call
payment-intents: Required (returns the bank list) · Response payload:html.
Step A — Fetch bank list
curl -X POST "$MIGO_BASE/api/v1/integrations/transactions/$UID/payment-intents" \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "processor": "globalPay-PSE" }'
Response — banks, fisTypes, userTypes, and accountTypes are all populated from the processor config (processorCfg.extras); the contents below are illustrative only:
{
"data": {
"banks": [{ "key": "1007", "value": "Bancolombia" }, …],
"fisTypes": [{ "key": "0", "value": "Natural" }, { "key": "1", "value": "Jurídica" }],
"userTypes": [{ "key": "CC", "value": "Cédula de Ciudadanía" }, …],
"accountTypes": [{ "key": "…", "value": "…" }, …]
}
}
Render selects for bank, fisType, userType and collect userName, email, fiscalNumber, installments.
Step B — Process payment
curl -X POST "$MIGO_BASE/api/v1/integrations/transactions/$UID/payments" \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"processor": "globalPay-PSE",
"data": {
"bank": { "key": "1007", "value": "Bancolombia" },
"fisType": { "key": "0", "value": "Natural" },
"userType": { "key": "CC", "value": "Cédula de Ciudadanía" },
"userName": "Test User",
"email": "test@example.com",
"fiscalNumber": "1020304050",
"installments": 1
}
}'
Response — the auto-submit form is at data.html (not data.value):
{
"success": true,
"message": "success",
"data": {
"uid": "trx_…",
"type": "html",
"html": "<form …></form>",
"cancelAt": null
}
}
Inject data.html into your page (it auto-submits to the bank). The customer authenticates inside their bank's portal and is bounced back to the merchant's successUrl / failureUrl. Status is delivered via the merchant callback (clientConfig.callback).
Both revert and refund are supported via POST $MIGO_BASE/revert and POST $MIGO_BASE/refund with body {"transactionUid":"$UID","processor":"globalPay-PSE"} (JWT-Bearer scheme).
Sandbox data
bank.key = "0"(test bank in QA) always approves.fiscalNumber = "1234567890"→ simulated decline.
Done checklist
- Bank list rendered.
- HTML auto-submitted.
- Bounce-back URL handled and webhook arrived.
Common errors across rails
The alternative-payments middleware raises 4-digit own-codes (not the ALI Gateway 7xxx catalog):
| HTTP | own-code | When |
|---|---|---|
| 400 | 5000 | Missing/invalid params (amount, channel, client, userId, customKeys, or processor) |
| 400 | — | processor not allowed for this client |
| 400 | 5004 | Client config not found |
| 400 | 2002 | Transaction create failed |
| 400 | 2003 | Amount outside the allowed range |
Status delivery
Payment status is delivered via the merchant callback you configure in clientConfig.callback — see Merchant Generic Callback. There is no fixed platform-defined webhook envelope.
Final checklist
- Merchant token sent as
Authorization: Bearer $MIGO_TOKEN; transaction created. -
nequiandglobalPay-PSEtested in sandbox. - Refund/void paths tested for
nequi,globalPay-PSE. - Customer journey covered for each rail's response shape (
payButton,html).