SPEI
Guía de Integración: Pago SPEI en OrkestaPay
Esta guía describe el flujo completo para integrar pagos mediante transferencia bancaria SPEI (Sistema de Pagos Electrónicos Interbancarios) en México usando la API de OrkestaPay.
Entorno de pruebas: Todos los ejemplos usan el endpoint de sandbox
https://api.sand.orkestapay.com. Para producción, reemplaza el dominio con el endpoint correspondiente.
Resumen del flujo
1. Autenticación → Obtener access_token
2. Crear método de pago → Obtener payment_method_id
3. Crear orden → Obtener order_id
4. Registrar pago → Obtener CLABE + referencia para el comprador
Recomendación: Guarda los IDs obtenidos en cada paso (
payment_method_id,order_id,payment_id) ya que los necesitarás en pasos posteriores y para el seguimiento de la transacción.
Paso 1 — Autenticación
Obtén un access_token llamando al servicio de autenticación de OrkestaPay con tus credenciales de API. Este token se usa como Bearer en todos los demás endpoints.
📘 Documentación: https://docs.orkestapay.com/docs/autenticación
El token tiene un tiempo de expiración. Implementa la lógica de refresco o re-autenticación según lo indique la documentación.
Paso 2 — Crear método de pago SPEI
Registra una intención de pago de tipo SPEI. Esto genera un payment_method_id que usarás al momento de registrar el pago.
Request
curl --request POST \
--url https://api.sand.orkestpay.com/v1/payment-methods \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data '{
"type": "SPEI",
"alias": "SPEI payment method"
}'| Campo | Tipo | Descripción |
|---|---|---|
type | string | Debe ser "SPEI" para transferencia bancaria en MX |
alias | string | Nombre descriptivo para identificar el método de pago |
Response
{
"payment_method_id": "pym_d8dc1499cd6f47ad9fb352ae35690c5c",
"alias": "SPEI payment method",
"type": "SPEI",
"status": "ACTIVE",
"created_at": "1781841077671",
"updated_at": "1781841077671"
}Guarda el
payment_method_id— lo necesitarás en el Paso 4.Nota sobre
created_at/updated_at: Los timestamps están en formato Unix Epoch en milisegundos (ms). Para convertirlos a fecha legible:new Date(1781841077671)en JavaScript odatetime.fromtimestamp(1781841077671 / 1000)en Python.
📘 Documentación: https://docs.orkestapay.com/reference/create-payment-method
Paso 3 — Crear orden
Registra el detalle de la compra: artículos, montos y datos del cliente. Esto representa el "checkout" de la transacción.
Request
curl --request POST \
--url https://api.sand.orkestapay.com/v1/orders \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data '{
"country_code": "MX",
"merchant_order_id": "1366656595193",
"currency": "MXN",
"subtotal_amount": 1000,
"total_amount": 990,
"discounts": [
{
"amount": 10
}
],
"products": [
{
"product_id": "7197",
"name": "Pantalla TCL Smart TV Serie A3 A343 HD Android TV 40",
"quantity": 1,
"unit_price": 1000
}
],
"customer": {
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]"
}
}'Campos principales del body:
| Campo | Tipo | Descripción |
|---|---|---|
country_code | string | Código ISO del país. Para México: "MX" |
merchant_order_id | string | ID único de tu sistema para esta orden (evita duplicados) |
currency | string | Moneda ISO 4217. Para pesos mexicanos: "MXN" |
subtotal_amount | number | Suma de productos sin aplicar descuentos |
total_amount | number | Monto final a cobrar (subtotal_amount - sum(discounts)) |
discounts | array | Lista de descuentos aplicados. La suma debe corresponder a subtotal - total |
products | array | Detalle de artículos incluidos en la orden |
customer | object | Datos del comprador |
Response
{
"order_id": "ord_466e5680ca3d44fa83045bd113d7a1df",
"status": "CREATED",
"expires_at": "1781927907513",
"merchant_order_id": "1366656595193",
"customer": {
"source": "ORDER",
"customer_id": "cus_21fa0cf02d1c4a73baf5b4f1c712c557",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"created_at": "1781841507423",
"updated_at": "1781841507423"
},
"placed_at": "1781841507513",
"country": "México",
"country_code": "MX",
"currency": "MXN",
"subtotal_amount": 1000,
"discounts": [
{
"amount": 10.00
}
],
"total_amount": 990,
"products": [
{
"product_id": "7197",
"quantity": 1,
"unit_price": 1000.00,
"name": "Pantalla TCL Smart TV Serie A3 A343 HD Android TV 40"
}
],
"order_type": "STANDARD"
}Guarda el
order_id— lo necesitarás en el Paso 4.Nota sobre
expires_at: La orden tiene una vigencia limitada. Si el comprador no realiza la transferencia antes de esta fecha, la orden expirará y deberás crear una nueva. Muestra este plazo al usuario en tu interfaz.
📘 Documentación: https://docs.orkestapay.com/reference/create-order
Paso 4 — Registrar pago
Con el payment_method_id y el order_id obtenidos en los pasos anteriores, registra el pago. La respuesta incluirá la CLABE y referencia que el comprador debe usar para realizar la transferencia desde su banca en línea.
Request
curl --request POST \
--url https://api.sand.orkestapay.com/v1/payments \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--header 'Idempotency-Key: {UUID_UNICO_POR_INTENTO}' \
--data '{
"payment_source": {
"type": "SPEI",
"payment_method_id": "{PAYMENT_METHOD_ID}"
},
"order_id": "{ORDER_ID}"
}'| Header | Descripción |
|---|---|
Idempotency-Key | UUID único por cada nuevo intento de pago. Reutilizar el mismo valor en un reintento evita pagos duplicados. |
Importante sobre
Idempotency-Key: Genera un nuevo UUID para cada intento de pago distinto (e.g.,crypto.randomUUID()en Node.js ouuid.uuid4()en Python). Si haces un reintento exactamente del mismo pago ante un error de red, puedes reutilizar el mismo key para garantizar idempotencia.
Response
{
"payment_id": "pay_bcd1d0cd28964567af02825088cd1bc2",
"order_id": "ord_466e5680ca3d44fa83045bd113d7a1df",
"status": "PAYMENT_ACTION_REQUIRED",
"payment_source": {
"type": "SPEI",
"payment_method_id": "pym_d8dc1499cd6f47ad9fb352ae35690c5c"
},
"amount": {
"requested": 102.00,
"currency": "MXN"
},
"user_action_required": {
"type": "OFFLINE_PAYMENT",
"offline_payment_provider": {
"reference": "1282938",
"bank": "Finco Pay",
"clabe": "734180000066931684",
"url_payment_receipt": "https://api.sand.orkestapay.com/public/v1/offline-payments/bank-transfers/0e5264367c474b0481fe777bd2e32587/receipt"
}
},
"transactions": [
{
"type": "REGISTER",
"transaction_id": "079d36ffe02b4979bb1754b560f837a3",
"status": "SUCCESS",
"amount": 102.00,
"provider": {
"merchant_provider_id": "mpv_c102dd2cef374873b16153616ebaf90c",
"provider_id": "prc_40000c08f7a649b1ab065b6158b2e0dc",
"name": "bank_transfer"
},
"created_at": "1781841416576"
}
],
"created_at": "1781841409679",
"updated_at": "1781841409679"
}Campos clave de la respuesta:
| Campo | Descripción |
|---|---|
status | Siempre será PAYMENT_ACTION_REQUIRED para SPEI — el pago está pendiente de la transferencia del comprador |
user_action_required.offline_payment_provider.clabe | CLABE interbancaria de 18 dígitos a la que el comprador debe transferir |
user_action_required.offline_payment_provider.reference | Referencia numérica que el comprador debe incluir en la transferencia |
user_action_required.offline_payment_provider.bank | Nombre del banco receptor |
user_action_required.offline_payment_provider.url_payment_receipt | URL para descargar el recibo con instrucciones de pago para el comprador |
Flujo post-pago: El estado
PAYMENT_ACTION_REQUIREDindica que la orden está activa y esperando la transferencia. OrkestaPay notificará el cambio de estado (e.g.,COMPLETEDoFAILED) vía webhook cuando el banco confirme la operación. Configura tu endpoint de webhook en el dashboard de OrkestaPay para recibir estas notificaciones.
📘 Documentación: https://docs.orkestapay.com/reference/create-payment
Resumen de IDs a persistir
| ID | Obtenido en | Para qué sirve |
|---|---|---|
access_token | Paso 1 | Autenticación en todos los endpoints |
payment_method_id | Paso 2 | Referenciar el método SPEI al crear el pago |
order_id | Paso 3 | Asociar la orden al pago; consultas de estado de orden |
payment_id | Paso 4 | Seguimiento y conciliación del pago |
clabe + reference | Paso 4 | Instrucciones que el comprador necesita para transferir |
Errores comunes
| Escenario | Causa probable |
|---|---|
401 Unauthorized | access_token expirado o inválido — re-autentica |
| Pago duplicado | Se envió la misma Idempotency-Key para dos intentos distintos |
| Orden expirada al pagar | El comprador no transfirió antes de expires_at — crea una nueva orden |
