Recipe template
This is the canonical structure for any country recipe. Copy it verbatim when adding a new market or rail. The structure is what makes the recipes consumable by both humans and integration agents.
## {Rail name} (`processorKey`)
> **Country:** … · **Type:** … · **Pre-call `payment-intents`:** … · **Response payload:** `url` | `qr` | `html` | `payButton` | `json`.
### Pre-requisites
- The merchant's `clientConfig.processors` includes `processorKey`.
- You have the long-lived 64-char merchant token (see [Authentication → Merchant token](/introduction/authentication#merchant-token)). Alternative Payments accept it as `Authorization: Bearer <token>`.
- Required user-collected fields: …
### Step 1 — Create the transaction
```bash
curl -X POST https://sb-mw.migopayments.com/api/v1/integrations/transactions \
-H "Authorization: Bearer $MIGO_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "amount": 1000, "channel": "web", "client": "your-client-slug", "userId": "+50200000000", "customKeys": { "orderId": "…" } }'
```
Required fields: `amount`, `channel`, `client`, `userId`, `customKeys`. Expected response (truncated):
```json
{
"success": true,
"data": {
"uid": "trx_…",
"paymentMethods": [ "processorKey", … ]
}
}
```
### Step 2 — (Only if required) Fetch payment intent
```bash
curl -X POST https://sb-mw.migopayments.com/api/v1/integrations/transactions/$UID/payment-intents \
-H "Authorization: Bearer $MIGO_TOKEN" \
-d '{ "processor": "processorKey" }'
```
Returns the metadata your frontend needs (banks, sessions). The `payment-intents` handler only special-cases a few processors (`globalPay-PSE`, `fri`, `nequi`); others return `{ "success": true, "data": null }`.
### Step 3 — Process payment
```bash
curl -X POST https://sb-mw.migopayments.com/api/v1/integrations/transactions/$UID/payments \
-H "Authorization: Bearer $MIGO_TOKEN" \
-d '{ "processor": "processorKey", "data": { … } }'
```
The success envelope is `{ "success": true, "message": "…", "data": { … } }`. Read the rail payload from `data.data` (and processor-specific keys like `data.html` for `globalPay-PSE`). There is no top-level `statusCode` field in the JSON body.
### Step 4 — Status delivery
Payment status is delivered via the merchant callback you configure in `clientConfig.callback` — the payload is whatever your callback `data` template defines, not a fixed platform envelope. See [Merchant Generic Callback](/card-payments/merchant-generic-callback).
> No outbound webhook signer exists in code today — the platform does not currently emit an `X-Migo-Signature` header.
### Sandbox data
- `…`
### Common errors
The alternative-payments middleware raises 4-digit own-codes (not the ALI Gateway `7xxx` catalog):
| HTTP | own-code | When |
|---|---|---|
| 400 | `5000` | Missing/invalid params |
| 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 |
### Done checklist
- [ ] `POST .../transactions` returned `processorKey` in `paymentMethods`.
- [ ] `POST .../payments` returned the expected `data.type`, payload read from `data.data`.
- [ ] Frontend rendered the correct surface.
- [ ] Merchant callback received with the expected status in sandbox.
Country pages stitch one of these blocks per rail; the country header at the top pre-fills the auth/setup section once for the whole page.