Efectivo

Guía de Integración: Pago en Tienda de Conveniencia en OrkestaPay

Esta guía describe el flujo completo para integrar pagos en efectivo en tiendas de conveniencia 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 referencia + código de barras 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 oficial.


Paso 2 — Crear método de pago en efectivo

Registra una intención de pago de tipo CASH. Esto genera un payment_method_id que usarás al momento de registrar el pago.

Request

curl --request POST \
     --url https://api.sand.orkestapay.com/v1/payment-methods \
     --header 'Accept: application/json' \
     --header 'Content-Type: application/json' \
     --header 'Authorization: Bearer {ACCESS_TOKEN}' \
     --data '{
         "type": "CASH",
         "alias": "Cash payment method"
     }'
CampoTipoDescripción
typestringDebe ser "CASH" para pago en tienda de conveniencia
aliasstringNombre descriptivo para identificar el método de pago

Response

{
    "payment_method_id": "pym_c79d63641e1243e9b64f5f6a7a8bae48",
    "alias": "Cash payment method",
    "type": "CASH",
    "status": "ACTIVE",
    "created_at": "1785172300000",
    "updated_at": "1785172300000"
}

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(1785172300000) en JavaScript o datetime.fromtimestamp(1785172300000 / 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:

CampoTipoDescripción
country_codestringCódigo ISO del país. Para México: "MX"
merchant_order_idstringID único de tu sistema para esta orden (evita duplicados)
currencystringMoneda ISO 4217. Para pesos mexicanos: "MXN"
subtotal_amountnumberSuma de productos sin aplicar descuentos
total_amountnumberMonto final a cobrar (subtotal_amount - sum(discounts))
discountsarrayLista de descuentos aplicados. La suma debe corresponder a subtotal - total
productsarrayDetalle de artículos incluidos en la orden
customerobjectDatos del comprador

Importante: Verifica que subtotal_amount - sum(discounts[].amount) == total_amount. Una inconsistencia puede provocar un error de validación en el API.

Response

{
    "order_id": "ord_c9ab42cbc49e479e8972c6f0a14310de",
    "status": "CREATED",
    "expires_at": "1785258726000",
    "merchant_order_id": "1366656595193",
    "customer": {
        "source": "ORDER",
        "customer_id": "cus_21fa0cf02d1c4a73baf5b4f1c712c557",
        "first_name": "John",
        "last_name": "Doe",
        "email": "[email protected]",
        "created_at": "1785172300000",
        "updated_at": "1785172300000"
    },
    "placed_at": "1785172326000",
    "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 el pago en tienda 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 referencia y el código de barras que el comprador necesita para pagar en la tienda de conveniencia.

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": "CASH",
             "payment_method_id": "{PAYMENT_METHOD_ID}"
         },
         "order_id": "{ORDER_ID}"
     }'
HeaderDescripción
Idempotency-KeyUUID ú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 o uuid.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_2a7f991dc7024fa3896f212bc0b3d6a2",
    "order_id": "ord_c9ab42cbc49e479e8972c6f0a14310de",
    "status": "PAYMENT_ACTION_REQUIRED",
    "payment_source": {
        "type": "CASH",
        "payment_method_id": "pym_c79d63641e1243e9b64f5f6a7a8bae48"
    },
    "amount": {
        "requested": 140.00,
        "currency": "MXN"
    },
    "user_action_required": {
        "type": "OFFLINE_PAYMENT",
        "offline_payment_provider": {
            "reference": "000000000000003235729294",
            "barcode_url": "https://references-dev.s3.amazonaws.com/00000000000000000092929405",
            "url_payment_receipt": "https://api-sand.tcpagos.mx/api/v2/transactions/public/xlfjjc5ptpqkocmp/transaction/voucher?application_id=32"
        }
    },
    "transactions": [
        {
            "type": "REGISTER",
            "transaction_id": "424801511369448d8398ce0b33ee6998",
            "status": "SUCCESS",
            "amount": 140.00,
            "code": "APPROVED",
            "provider": {
                "merchant_provider_id": "mpv_2ac107f7f4ba4849a9d9ec814723e966",
                "provider_id": "prc_4147ebfe2c264e1a8ddc6f80b83fb123",
                "name": "tcpagos"
            },
            "created_at": "1785172326679"
        }
    ],
    "created_at": "1785172324833",
    "updated_at": "1785172324833"
}

Campos clave de la respuesta:

CampoDescripción
statusSiempre será PAYMENT_ACTION_REQUIRED para CASH — el pago está pendiente de realizarse en tienda
user_action_required.offline_payment_provider.referenceReferencia numérica que el comprador presenta en la caja de la tienda
user_action_required.offline_payment_provider.barcode_urlURL de la imagen del código de barras escaneable en caja
user_action_required.offline_payment_provider.url_payment_receiptURL del recibo con las instrucciones completas para pagar en tienda

⚠️ Muestra la referencia y el recibo al comprador. Una vez registrado el pago, debes presentarle al usuario la referencia (reference) y/o el código de barras (barcode_url) para que pueda acudir a la tienda. Lo más recomendable es redirigirlo o mostrarle el recibo completo disponible en url_payment_receipt, ya que incluye todas las instrucciones del proceso de pago en caja.

Flujo post-pago: El estado PAYMENT_ACTION_REQUIRED indica que la orden está activa y esperando el pago en tienda. OrkestaPay notificará el cambio de estado (e.g., COMPLETED o FAILED) vía webhook cuando la tienda 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

IDObtenido enPara qué sirve
access_tokenPaso 1Autenticación en todos los endpoints
payment_method_idPaso 2Referenciar el método CASH al crear el pago
order_idPaso 3Asociar la orden al pago; consultas de estado de orden
payment_idPaso 4Seguimiento y conciliación del pago
referencePaso 4Código que el comprador presenta en caja para realizar el pago
barcode_urlPaso 4Imagen del código de barras escaneable en la tienda
url_payment_receiptPaso 4Recibo con instrucciones completas para mostrar o enviar al comprador

Errores comunes

EscenarioCausa probable
401 Unauthorizedaccess_token expirado o inválido — re-autentica
Orden rechazada por montossubtotal_amount - discounts != total_amount
Pago duplicadoSe envió la misma Idempotency-Key para dos intentos distintos
Orden expirada al pagarEl comprador no pagó en tienda antes de expires_at — crea una nueva orden
Webhook no recibidoEl endpoint de webhook no está configurado o no responde con 2xx
Comprador no puede pagar en tiendaNo se mostraron la referencia o el recibo — asegúrate de exponer url_payment_receipt en tu UI


Did this page help you?