Sandbox Cheat Sheet
Everything you need to make your first end-to-end Payment Link transaction in Sandbox, on a single page. Bookmark this when you start an integration.
- Middleware Sandbox (
https://sb-mw.migopayments.com) β Payment Links, hosted webview, tokenization, charges. This is what you call to get aURLfor your customer. - Wallet Gateway QA (
https://ali-qa.ali.app/rest) β wallet, cards, users. Different credentials and flow; see Quick Start and Environments.
This page focuses on the Middleware Sandbox because that is where Payment Links live.
Base URLs (Middleware)β
| Surface | Sandbox | Production |
|---|---|---|
| API host | https://sb-mw.migopayments.com | https://mw.migopayments.com |
| Hosted webview | https://sandbox.migopayments.com | https://web.migopayments.com |
| OpenAPI reference | /api-reference/migo-api | same β toggle the server in the Scalar UI |
Credentials checklistβ
Before you can call POST /transactions (Payment Links) or POST /api/v1/integrations/transactions (Alternative Payments), you need:
| Item | What it looks like | How to get it |
|---|---|---|
client slug | Short string, e.g. migoDeveloper | Created when Migo onboards your application |
| Merchant token | 64-char hex, e.g. b6a615d8...0ba65c1 | Issued together with the client slug. The same token authenticates both Payment Links and Alternative Payments β only the header format changes per endpoint. |
(Alternative) privateKey + publicKey | UUID-shaped pair | Issued for browser-side /transactions-hook integrations |
Header format depends on the endpointβ
| Endpoint | Header value |
|---|---|
POST /transactions (Payment Link) | Authorization: <token> β no Bearer prefix |
POST /api/v1/integrations/transactions[β¦] (Alternative Payments) | Authorization: Bearer <token> β Bearer required |
See Authentication β Header format by endpoint for the canonical matrix.
Known sandbox client slugsβ
| Slug | Country | Rails commonly enabled in Sandbox |
|---|---|---|
migoDeveloper | Guatemala | zigi, akisiQR, bamPaymentButton, quickPayQR, bancoIndustrial, pronet |
Confirm the rails enabled for your slug by reading data.paymentMethods in the response of POST /api/v1/integrations/transactions β that array is the source of truth.
Minimal requestβ
curl -X POST https://sb-mw.migopayments.com/transactions \
-H 'Content-Type: application/json' \
-H 'Authorization: <your-sandbox-merchant-token>' \
-d '{
"amount": 1,
"userId": "+50224865444",
"channel": "wa",
"client": "<your-client-slug>",
"ads": []
}'
Expected response:
{
"uid": "Ypo5z2zTpLqWoe3eVvZMH",
"reference": "CLIENT020007SB",
"URL": "https://sandbox.migopayments.com/?orderId=Ypo5z2zTpLqWoe3eVvZMH"
}
Field URL is uppercase. Open it in a browser to render the hosted webview.
Minimal request β Alternative Payments (akisiQR)β
For the direct APM flow (render the QR yourself instead of opening the webview), reuse the same merchant token but add the Bearer prefix:
# 1) Create transaction
curl -X POST 'https://sb-mw.migopayments.com/api/v1/integrations/transactions' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-sandbox-merchant-token>' \
-d '{
"amount": 50,
"channel": "web",
"client": "migoDeveloper",
"userId": "+50224865444",
"customKeys": { "orderId": "demo-1" }
}'
# β 201 { "data": { "uid": "...", "paymentMethods": ["akisiQR","zigi","quickPayQR","pronet"], "expireAt": 11999 } }
# 2) Process akisiQR β uses the uid from step 1
curl -X POST 'https://sb-mw.migopayments.com/api/v1/integrations/transactions/<uid>/payments' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <your-sandbox-merchant-token>' \
-d '{ "processor": "akisiQR", "data": {} }'
# β 200 { "data": { "type": "base64", "data": "data:image/png;base64,β¦" } }
The data.data value is a complete data:image/png;base64,β¦ URI β drop it into <img src=...>. See Recipes β Guatemala β Akisi QR for the full per-rail walkthrough.
Field cookbookβ
| Field | Sandbox-friendly value | Notes |
|---|---|---|
amount | 1 for the cheapest test, any value inside your client's configured range | Outside the range β ownCode 2003 |
userId | E.164 phone, e.g. +50224865444 (Guatemala) | The Sandbox does not actually deliver SMS / WhatsApp, but the format must be parseable |
channel | wa, sms, email, web, app | Depends on what is enabled per client. Unknown values β ownCode 5000 |
client | Your slug | Wrong slug β ownCode 5004 |
currency | GTQ, USD, MXN, CRC, HNL, DOP, COP, SVC | If omitted, Migo uses your client's first configured currency |
externalId | Any string you control, e.g. WEB-${Date.now()} | Returned in the Merchant Generic Callback payload |
ads | [] | Reserved β always send the empty array if unused |
Test cards inside the webviewβ
Once the customer opens the URL, the hosted webview asks for card data. The test cards that work depend on the card processor configured for your client (for Guatemala this is Cybersource). A few common Cybersource examples:
| PAN | Brand | Behavior |
|---|---|---|
4111111111111111 | Visa | Valid (approves) |
4456530000001096 | Visa | Valid with 3DS challenge |
4000000000000002 | Visa | Declines the transaction |
Use any future expiry, any valid CVV (4 digits for Amex, 3 otherwise). The approval/decline outcome (including 3DS behavior) is driven by the test card you use, not by a request field.
The full, authoritative card list per processor (Cybersource, FAC 2, Visa Epay, PusPayment, β¦) lives in Testing your integration β Test cards. Confirm which processor applies to your client before picking a card.
Receiving the resultβ
The terminal status reaches your backend through the Merchant Generic Callback β a POST from Migo to a URL you registered with support. Standard payload:
{
"reference": "CLIENT020007SB",
"uid": "Ypo5z2zTpLqWoe3eVvZMH",
"country": "GT",
"currency": "GTQ",
"channel": "WhatsApp",
"status": "approved",
"amount": 1,
"externalId": "ext_auth_123",
"createdAt": "06/05/2026 09:31:00",
"transactionId": "txn_1029384756",
"paymentMethodType": "credit_card"
}
Authenticate the request with the static header you registered with Migo (no HMAC). Full details in Merchant Generic Callback.
Common Sandbox errorsβ
| HTTP | ownCode | Likely cause | Quick fix |
|---|---|---|---|
| 401 | 2007 | Token sent with Bearer prefix, or wrong env credentials | Send the raw token; double-check Sandbox vs Production |
| 409 | 5000 | Missing required field, wrong type, or unknown channel | Verify body matches the schema in Create a Payment Link |
| 409 | 5004 | Wrong client slug | Copy the slug as Migo provided it (case-sensitive) |
| 400 | 2003 | amount outside configured range | Try amount: 1; ask Migo for the configured min/max |
Full catalog: Error Catalog β Payment Link / Middleware ownCodes.
What to copy into your .envβ
MIGO_BASE_URL=https://sb-mw.migopayments.com
MIGO_CLIENT=<your-client-slug>
MIGO_MERCHANT_TOKEN=<your-sandbox-merchant-token>
MIGO_DEFAULT_CHANNEL=web
MIGO_DEFAULT_CURRENCY=GTQ
Never commit these. For browser integrations use the alternative key-pair flow described in Create a Payment Link β alternative endpoint, and scope the keys to the smallest amount range you can.
Going to productionβ
When Sandbox is green, walk through Go-live checklist. Production credentials, base URLs, and webhook receivers are different β none of the Sandbox values above carry over.