Skip to main content
Migo Docs

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

  • paymentMethods contained nequi.
  • payButton response read from data.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):

HTTPown-codeWhen
4005000Missing/invalid params (amount, channel, client, userId, customKeys, or processor)
400processor not allowed for this client
4005004Client config not found
4002002Transaction create failed
4002003Amount 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.
  • nequi and globalPay-PSE tested in sandbox.
  • Refund/void paths tested for nequi, globalPay-PSE.
  • Customer journey covered for each rail's response shape (payButton, html).