Core

paymentData shapes by method

Every direct-charge payment response includes a `paymentData` block whose shape depends on the method (SPEI vs OXXO vs PIX vs card vs …). This page enumerates every shape so you can render the right UI without trial and error.

On direct-charge flow (POST /api/v1/payments without hosted checkout) the response includes a paymentData block that carries the method-specific instructions your UI needs to show the customer (a QR code for PIX, a CLABE for SPEI, a voucher reference for cash retailers, a redirect URL for card, etc.). Below is the shape per method slug. When in doubt or you don't want to render per-method UI yourself, use POST /api/v1/checkout/sessions — we handle the UI for every method.

The envelope

json
{
  "transactionId": "TXN-...",
  "status": "pending",
  "paymentMethodId": "1001",
  "paymentFormUrl": "https://secure-int.key2pay.io/checkout?token=...",
  "paymentData": {
    "method": "<slug>",
    // method-specific fields below
  }
}
Stability promise: the method key inside paymentData always matches the slug taxonomy (spei, oxxo,pix, voucher,bank_transfer, card,debit, …). Switch on it. New methods may add fields but we never rename or remove existing keys without a versioned migration.

spei

json
{
  "method": "spei",
  "clabe": "012345678901234567",
  "bankName": "STP"
}

Display the clabe with a one-tap copy button and tell the customer to send the exact amount from their banking app to that CLABE on STP. Customer has ~24h before the tx auto-transitions to expired.

oxxo

json
{
  "method": "oxxo",
  "voucherCode": "8014 0123 4567 8901",
  "voucherUrl": "https://secure-int.key2pay.io/voucher/oxxo/TXN-...",
  "reference": "OXXO-2026051200001",
  "expiresAt": "2026-05-19T20:27:53.561Z"
}

The customer prints the voucher (voucherUrl) or shows the code at any OXXO store. ~7 days to pay before expiry.

pix

json
{
  "method": "pix",
  "qrCode": "00020126360014BR.GOV.BCB.PIX0114TXN-...",
  "qrCodeUrl": "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=...",
  "copyPasteCode": "00020126360014BR.GOV.BCB.PIX0114TXN-...520400005303986540...",
  "expiresAt": "2026-05-12T20:42:53.561Z"
}

Render the QR for mobile customers + a copy-paste textbox with copyPasteCode for desktop customers (PIX accepts both). ~15 min window typically — check expiresAt.

voucher (Walmart, 7-Eleven, Soriana, Circle K, …)

json
{
  "method": "voucher",
  "retailer": "Walmart",
  "voucherCode": "K2P-XX-0123456789",
  "voucherUrl": "https://secure-int.key2pay.io/voucher/walmart/TXN-...",
  "reference": "WMT-2026051200001",
  "expiresAt": "2026-05-19T20:27:53.561Z"
}

retailer reflects the specific paymentMethodId picked — 1009 = Walmart, 1010 = Waldo's, etc. Each retailer has its own voucher format but the response shape is uniform.

bank_transfer (BBVA, Scotiabank, Banco Azteca, Afirme, …)

json
{
  "method": "bank_transfer",
  "bankName": "BBVA Bancomer",
  "accountNumber": "0123 4567 8901 2345",
  "accountHolder": "KEY2PAY MERCHANT SERVICES SA DE CV",
  "reference": "BBVA-2026051200001",
  "expiresAt": "2026-05-13T20:27:53.561Z"
}

card / debit

json
{
  "method": "card",
  "redirectUrl": "https://secure-int.key2pay.io/checkout/3ds?token=...",
  "requires3ds": true
}

Cards always redirect to the upstream provider's hosted form for PAN entry — keeps you out of PCI scope. requires3ds tells you whether a 3DS challenge is expected.

When in doubt — use hosted checkout

If you don't want to switch on the method and render a different UI per method, use POST /api/v1/checkout/sessions instead. We host the UI and the response just gives you a single checkoutUrl to redirect to. See the hosted-checkout doc for the full flow.