🚀 Lanzamiento v2.3: Activa y desactiva métodos de pago para tu Conekta Checkout desde el Panel, sin tocar tu código. Ver documentación →

Reutilización de referencia recurrente de efectivo

Cobra varias órdenes con la misma referencia de efectivo de tu cliente

Si cobras a un mismo cliente de forma periódica (mensualidades, renovaciones, abonos) y quieres que siempre pague con la misma referencia de efectivo, crea tus órdenes con el parámetro reuse_customer_cash_reference: true. La orden usará la referencia recurrente de efectivo de tu cliente en lugar de generar una nueva. Cuando el cliente pague ese monto en tienda, Conekta liquidará esa orden.

Es el equivalente en efectivo de la reutilización de CLABE para SPEI.

Cómo funciona

sequenceDiagram
    participant Dev as Tu servidor
    participant Conekta
    participant Tienda as Tienda / BBVA
    Dev->>Conekta: POST /customers/:id/payment_sources (cash_recurrent)
    Conekta-->>Dev: Referencia recurrente del cliente
    Dev->>Conekta: POST /orders (reuse_customer_cash_reference: true)
    Conekta-->>Dev: Orden pending_payment con la referencia del cliente
    Tienda->>Conekta: Pago con la referencia y el monto de la orden
    Conekta-->>Dev: Webhooks order.paid / charge.paid
  1. Creas la referencia recurrente una sola vez. Se guarda como un payment source de tipo cash_recurrent en el cliente.
  2. Creas una orden por cada cobro. Con reuse_customer_cash_reference: true, el cargo de efectivo usa la referencia del cliente, con el monto de esa orden.
  3. El cliente paga en tienda con su referencia de siempre y el monto de la orden.
  4. Conekta liquida la orden. Busca la orden pendiente de ese cliente con la misma referencia y el mismo monto, la marca como pagada y te lo notifica por webhook.

La referencia recurrente no se modifica: pagar o cancelar una orden no la desactiva, y puedes seguir usándola en órdenes nuevas.

Requisitos

1. Añade tu llave privada y versión del API

  • Tu API key en el header de autenticación: --header 'Authorization: Bearer key_xxxxxxxxxxxxxxxxxxxxxxxx'
  • La versión del API en el header accept: 'accept: application/vnd.conekta-v2.3.0+json'

2. Crea la referencia recurrente del cliente

Si tu cliente todavía no tiene una referencia recurrente de efectivo, créala como un payment source de tipo cash_recurrent:

curl --request POST \
  --url https://api.conekta.io/customers/cus_2xHJayvPVd3BpmdC7/payment_sources \
  --header 'accept: application/vnd.conekta-v2.3.0+json' \
  --header 'content-type: application/json' \
  --header 'Authorization: Bearer key_xxxxxxxxxxxxxxxxxxxxxxxx' \
  --data '{
    "type": "cash_recurrent"
  }'

Respuesta:

{
  "id": "off_ref_2xHJayvPVd3BpmdC8",
  "object": "payment_source",
  "provider": "Cash",
  "type": "cash_recurrent",
  "reference": "10001XXXXXXXXXXX0104",
  "barcode": "10001XXXXXXXXXXX0104",
  "barcode_url": "https://barcode/url.png",
  "expires_at": 0,
  "created_at": 1790633754,
  "parent_id": "cus_2xHJayvPVd3BpmdC7",
  "agreements": [
    {
      "provider": "bbva_cash_in",
      "agreement": "2409526"
    }
  ]
}
✅

El valor de reference es la referencia que tu cliente usará en todas sus órdenes. Si tu cuenta tiene BBVA, muestra a tu cliente el número de convenio (agreement) junto con la referencia: lo necesita para pagar en practicajas o banca móvil de BBVA.

3. Crea una orden que reutilice la referencia

Envía reuse_customer_cash_reference: true junto con customer_info.customer_id y un cargo de tipo cash. Los campos del ejemplo son los mínimos; para conocer el resto revisa la REST API.

La orden solo se puede pagar mientras su cargo no haya vencido. El vencimiento del cargo (payment_method.expires_at) se fija así:

  • Si envías charges[].payment_method.expires_at (fecha en formato UNIX), se usa ese valor.
  • Si no lo envías y tu cuenta tiene configurados días de vencimiento por defecto para referencias, vence en esos días.
  • Si no aplica ninguno de los dos, el cargo vence un mes después de crearse.

El vencimiento es de la orden, no de la referencia: la referencia recurrente del cliente sigue vigente para órdenes nuevas.

curl --request POST \
  --url https://api.conekta.io/orders \
  --header 'accept: application/vnd.conekta-v2.3.0+json' \
  --header 'content-type: application/json' \
  --header 'Authorization: Bearer key_xxxxxxxxxxxxxxxxxxxxxxxx' \
  --data '{
    "currency": "MXN",
    "reuse_customer_cash_reference": true,
    "customer_info": {
      "customer_id": "cus_2xHJayvPVd3BpmdC7"
    },
    "line_items": [{
      "name": "Mensualidad octubre",
      "unit_price": 50000,
      "quantity": 1
    }],
    "charges": [{
      "payment_method": {
        "type": "cash"
      }
    }]
  }'

Respuesta:

{
  "livemode": true,
  "amount": 50000,
  "currency": "MXN",
  "payment_status": "pending_payment",
  "customer_info": {
    "customer_id": "cus_2xHJayvPVd3BpmdC7",
    "object": "customer_info"
  },
  "object": "order",
  "id": "ord_2tXx9jDpCqIrjVKZ",
  "metadata": {
    "reuse_customer_cash_reference": true
  },
  "charges": {
    "object": "list",
    "has_more": false,
    "total": 2,
    "data": [
      {
        "id": "6abaedb171b62300012a240d",
        "status": "pending_payment",
        "amount": 50000,
        "payment_method": {
          "object": "cash_payment",
          "type": "cash",
          "product_type": "cash_in",
          "reference": "10001XXXXXXXXXXX0104",
          "barcode_url": "https://barcode/url.png",
          "agreement": null,
          "expires_at": 1790834399
        },
        "order_id": "ord_2tXx9jDpCqIrjVKZ"
      },
      {
        "id": "6abaedb171b62300012a2415",
        "status": "pending_payment",
        "amount": 50000,
        "payment_method": {
          "object": "cash_payment",
          "type": "cash",
          "product_type": "bbva_cash_in",
          "reference": "10001XXXXXXXXXXX0104",
          "barcode_url": "https://barcode/url.png",
          "agreement": "2409526",
          "expires_at": 1790834399
        },
        "order_id": "ord_2tXx9jDpCqIrjVKZ"
      }
    ]
  }
}
✅

La referencia 10001XXXXXXXXXXX0104 es la misma del paso 2. Si tu cuenta tiene varias redes de efectivo, la orden trae un cargo por red, todos con la misma referencia; el de BBVA usa el convenio recurrente. Cuando el cliente paga en una red, los demás cargos de la orden se cancelan.

4. Recibe la confirmación del pago

Cuando el cliente paga en tienda con su referencia, Conekta busca la orden pendiente creada con reuse_customer_cash_reference: true que tenga esa referencia y ese monto, y que no haya vencido. Esa orden se marca como pagada y recibirás los eventos charge.paid y order.paid en tu webhook.

🚧

Si usas la aprobación de pagos por webhook de la referencia recurrente: mientras el cliente tenga una orden pendiente creada con reuse_customer_cash_reference: true, Conekta no te envía la consulta de aprobación. En Conekta Efectivo, la tienda recibe directamente el monto de la orden pendiente y el pago se aplica a esa orden.

❗

Verifica siempre la firma de los webhooks antes de procesarlos. Consulta Autenticación de webhooks.

Ten en cuenta lo siguiente:

  • El monto debe coincidir exactamente. Si el cliente paga un monto que no corresponde a ninguna orden pendiente con el flag, el pago sigue el flujo normal de la referencia recurrente: Conekta consulta tu webhook para aprobarlo y genera una orden nueva.
  • Si hay varias órdenes pendientes con el mismo monto, el pago liquida la más reciente. Para evitar confusiones, cancela las órdenes que ya no quieras cobrar.
  • Un pago se aplica una sola vez. Si la red reenvía la misma notificación, Conekta la reconoce como duplicada y no liquida otra orden pendiente.
  • Dos pagos del mismo monto seguidos. Si el cliente paga dos órdenes del mismo monto en pocos minutos (por ejemplo, dos mensualidades el mismo día), el segundo pago puede rechazarse con el mensaje "El pago está en proceso" mientras se confirma el primero. Una vez confirmado el primer pago, lo que ocurre en unos 10 minutos, el cliente puede hacer el segundo.

5. Crea las siguientes órdenes

Para el siguiente cobro, repite el paso 3 con reuse_customer_cash_reference: true. No necesitas crear otra referencia.

curl --request POST \
  --url https://api.conekta.io/orders \
  --header 'accept: application/vnd.conekta-v2.3.0+json' \
  --header 'content-type: application/json' \
  --header 'Authorization: Bearer key_xxxxxxxxxxxxxxxxxxxxxxxx' \
  --data '{
    "currency": "MXN",
    "reuse_customer_cash_reference": true,
    "customer_info": {
      "customer_id": "cus_2xHJayvPVd3BpmdC7"
    },
    "line_items": [{
      "name": "Mensualidad noviembre",
      "unit_price": 50000,
      "quantity": 1
    }],
    "charges": [{
      "payment_method": {
        "type": "cash"
      }
    }]
  }'
📌

La referencia es la misma en todas las órdenes del cliente, así que puede pagar siempre con el mismo número o código de barras.


Pruebas

En modo de pruebas (con tus llaves de pruebas), los cargos en efectivo se marcan como pagados automáticamente unos 30 segundos después de crear la orden, y recibes los eventos charge.paid y order.paid en tu webhook. Úsalo para probar que tu integración crea la orden con la referencia del cliente y procesa las notificaciones de pago.

📌

En modo de pruebas no se simula el pago en tienda con la referencia, así que la búsqueda de la orden por referencia y monto solo ocurre con pagos reales.


Manejo de errores

ErrorCausaSolución
422 customer_info.customer_id.missingEnviaste reuse_customer_cash_reference: true sin customer_info.customer_id.Envía el customer_id del cliente que tiene la referencia recurrente.
404 offline_recurrent_reference.not_foundEl cliente no tiene una referencia cash_recurrent, o tu red BBVA no tiene convenio recurrente configurado.Crea la referencia (paso 2). Si usas BBVA, contacta a tu ejecutivo para configurar el convenio recurrente.
422 reuse_customer_cash_reference.invalid_datatypeEnviaste el parámetro con un valor que no es booleano, por ejemplo "yes".Envía true o false.

Consulta el catálogo completo en Códigos de error HTTP.

Error: customer_id faltante

{
  "details": [
    {
      "debug_message": "The \"customer_info attribute customer_id\" is missing.",
      "message": "El parametro customer_id\" es requerido.",
      "param": "customer_info.customer_id",
      "code": "conekta.errors.parameter_validation.customer_info.customer_id.missing"
    }
  ],
  "object": "error",
  "type": "parameter_validation_error",
  "log_id": "xxxxxxxxxxxxxxxxxxxx"
}

HTTP Status: 422 Unprocessable Entity

Error: referencia recurrente no encontrada

{
  "details": [
    {
      "debug_message": "Recurrent reference not found",
      "message": "Referencia recurrente no encontrada",
      "code": "conekta.errors.resource_not_found.processing.offline_recurrent_reference.not_found"
    }
  ],
  "object": "error",
  "type": "resource_not_found_error",
  "log_id": "xxxxxxxxxxxxxxxxxxxx"
}

HTTP Status: 404 Not Found

Para saber cuál de las dos causas aplica, consulta el cliente (GET /customers/cus_2xHJayvPVd3BpmdC7):

  • Si en payment_sources no hay una referencia cash_recurrent, créala (paso 2).
  • Si la referencia existe y tu cuenta tiene BBVA, el error viene del convenio recurrente. Cuando el convenio está configurado, agreements de la referencia incluye bbva_cash_in; si no aparece, contacta a tu ejecutivo de Conekta.

Error: tipo de dato inválido

{
  "details": [
    {
      "debug_message": "Invalid datatype for \"reuse_customer_cash_reference\" expecting at least Boolean.",
      "message": "\"reuse_customer_cash_reference\" tiene un tipo inválido.",
      "param": "reuse_customer_cash_reference",
      "code": "conekta.errors.parameter_validation.reuse_customer_cash_reference.invalid_datatype"
    }
  ],
  "object": "error",
  "type": "parameter_validation_error"
}

HTTP Status: 422 Unprocessable Entity


Comportamiento por defecto

Si no envías reuse_customer_cash_reference o lo envías en false, cada orden de efectivo genera una referencia única nueva, distinta de la referencia recurrente del cliente. Consulta Cargo único en efectivo.

Relacionado


Did this page help you?