Esta guía explica cómo recolectar un método de pago de tu cliente para luego mandar cargos automáticos que se realicen sin su intervención. Los cargos automáticos te permiten cobrar a tus clientes de forma recurrente o puntual sin que ellos tengan que autorizar cada transacción individualmente. Una vez que tienes un método de pago enlazado a un cliente, puedes hacer cargos sin intervención del usuario.
Los cargos automáticos requieren que el cliente haya proporcionado previamente su consentimiento y un método de pago válido.

1. Crea un cliente

El primer paso es crear un cliente en tu sistema. Este cliente será quien proporcionará el método de pago para los cargos automáticos.
POST https://api.quentli.com/v1/customers
{
  "input": {
    "name": "María González",
    "username": "12345",
    "email": "maria@ejemplo.com",
    "phoneNumber": "+525555123456"
  }
}

2. Recolecta un método de pago

Antes de realizar cargos automáticos, el cliente debe proporcionar un método de pago válido (tarjeta de crédito/débito o cuenta bancaria). Este paso se realiza a través del Portal de Clientes, donde se le solicita al usuario que guarde su método de pago para cargos futuros. Tienes 2 opciones para recolectar un método de pago:
  1. En una sesión de pago (PaymentSession)
  2. En una sesión de registro de método de pago

Opción 1: En una sesión de pago (PaymentSession)

POST https://api.quentli.com/v1/payment-sessions
{
  "input": {
    "returnUrl": "https://miapp.com/success",
    "cancelUrl": "https://miapp.com/declined",
    "customer": {
      "name": "Mariana López",
      "externalId": "1337"
    },
    "expiresAt": "2025-04-22T15:47:15.250Z",
    "description": "Mensualidad",
    "amount": 239000,
    "currency": "MXN"
  }
}

Opción 2: En una sesión de registro de método de pago

Esta modalidad es experimental. Por favor ponte en contacto con nosotros para obtener más información.

3. Realiza un cargo automático

Una vez que tienes un cliente con un método de pago válido, puedes realizar cargos automáticos usando el endpoint de pagos.
El endpoint de pagos (/v1/payments) se encuentra actualmente en etapa beta y puede estar sujeto a cambios.

Ejemplo de solicitud

POST https://api.quentli.com/v1/payments
{
  "input": {
    // El monto a cobrar (en centavos)
    "amount": 399900,
    "currency": "MXN",
    "description": "Mensualidad",
    // El ID de un método de pago (tarjeta o cuenta bancaria)
    "paymentMethodId": "pm_1234567890",
    "customerId": "cus_1234567890",
    // Este campo es importante para que el cargo se intente de forma inmediata
    "makeAttempt": true,
    // Campos arbitrarios que serán registrados en el objeto Payment
    "meta": {
      "orderId": "order_1234567890",
      "serviceType": "subscription"
    }
  }
}

Campos relevantes

  • amount: El monto a cobrar en centavos. Por ejemplo, $3,999.00 MXN = 399900 centavos.
  • paymentMethodId: El identificador del método de pago previamente recolectado del cliente.
  • customerId: El identificador del cliente al que se le realizará el cargo.
  • description: Una descripción clara del concepto que se está cobrando.
  • makeAttempt: Si es true, se hará el intento de cargo al enviar la petición. Si es false, se creará el pago pero no se hará el intento de cargo.
  • metadata: Información adicional que quieras asociar con el pago para tu referencia.

Posibles respuestas

Intento exitoso

Cuando el cargo es exitoso, verás la propiedad attempt.success como true.
Respuesta (intento exitoso)
{
    "payment": {
        "id": "p_1234567890",
        "createdAt": "2025-01-15T21:00:00.000Z",
        "amount": 399900,
        "currency": "MXN",
        "type": "CARD",
        "status": "COMPLETED",
        "description": "Mensualidad",
        "paymentMethodId": "pm_1234567890",
        "customerId": "cus_1234567890",
        "meta": {
            "orderId": "order_1234567890",
            "serviceType": "subscription"
        },
    },
    "attempt": {
      "id": "pa_1234567890",
      "createdAt": "2025-01-15T21:00:00.000Z",
      "success": true,
      "scheduled": false,
      "wasAttemptedByOrganization": true,
      "errorType": null,
      "attemptNumber": 1
    },
    "customer": {
      "id": "cus_1234567890",
      "name": "Alicia Ríos",
      "email": "aliciarr@ejemplos.com",
      "phoneNumber": "<número_de_celular>",
      "username": "12345",
      "meta": {}
    }
}

Intento fallido

Para identificar un cargo fallido, debes revisar el campo success. Puedes obtener el motivo del rechazo usando el campo errorType del objeto attempt.
Toma en cuenta que cuando un intento es fallido, el código HTTP de la respuesta será 200
Respuesta (intento fallido)
{
    "payment": {
        "id": "p_1234567890",
        "createdAt": "2025-01-15T21:00:00.000Z",
        "amount": 399900,
        "currency": "MXN",
        "type": "CARD",
        "status": "INCOMPLETE",
        "description": "Mensualidad",
        "paymentMethodId": "pm_1234567890",
        "customerId": "cus_1234567890",
        "meta": {
            "orderId": "order_1234567890",
            "serviceType": "subscription"
        },
    },
    "attempt": {
      "id": "pa_1234567890",
      "createdAt": "2025-01-15T21:00:00.000Z",
      "success": false,
      "scheduled": false,
      "wasAttemptedByOrganization": true,
      "errorType": "INSUFFICIENT_FUNDS",
      "attemptNumber": 1
    },
    "customer": {
      "id": "cus_1234567890",
      "name": "Alicia Ríos",
      "email": "aliciarr@ejemplos.com",
      "phoneNumber": "<número_de_celular>",
      "username": "12345",
      "meta": {}
    }
}

Intento iniciado

Cuando el método de pago que se usa es de tipo DIRECT_DEBIT, el pago se creará con estado INITIATED y la propiedad attempt será null. En estos casos, para monitorear el resultado, debes usar un webhook de tipo PAYMENT_ATTEMPT_SUCCEEDED o PAYMENT_ATTEMPT_FAILED.
Esto solo aplica para pagos con domiciliación bancaria (tipo DIRECT_DEBIT). Los pagos con tarjeta de crédito o débito se procesan de forma inmediata.
Respuesta (intento iniciado)
{
    "payment": {
        "id": "p_1234567890",
        "createdAt": "2025-01-15T21:00:00.000Z",
        "amount": 399900,
        "currency": "MXN",
        "type": "CARD",
        "status": "INITIATED",
        "description": "Mensualidad",
        "paymentMethodId": "pm_1234567890",
        "customerId": "cus_1234567890",
        "meta": {
            "orderId": "order_1234567890",
            "serviceType": "subscription"
        },
    },
    // Este campo será null para pagos con domiciliación bancaria
    "attempt": null,
    "customer": {
      "id": "cus_1234567890",
      "name": "Alicia Ríos",
      "email": "aliciarr@ejemplos.com",
      "phoneNumber": "<número_de_celular>",
      "username": "12345",
      "meta": {}
    }
}

Formas de pago soportadas

Este endpoint soporta dos formas de pago, cada una con diferentes tiempos de procesamiento:
Lo que determina qué forma de pago se usa es el tipo del método de pago (PaymentMethod.type) que proporcionas en el campo paymentMethodId al mandar el pago.

Tarjetas de crédito/débito (CARD)

Los pagos con tarjeta de crédito o débito se procesan de forma inmediata. Obtienes la confirmación del resultado del pago en tiempo real a través de la respuesta de la petición a POST /v1/payments.

Domiciliación bancaria (DIRECT_DEBIT)

Los pagos mediante domiciliación bancaria (cuentas CLABE) no se confirman inmediatamente. El proceso funciona así:
  1. Al crear el pago: Recibes una respuesta con estado INITIATED
  2. Procesamiento: El cargo se envía al sistema bancario
  3. Confirmación: Debes esperar hasta el siguiente día hábil para obtener la respuesta definitiva (mediante webhooks)

Ejemplo de respuesta

{
    "payment": {
        "id": "p_1234567890",
        "createdAt": "2025-01-15T21:00:00.000Z",
        "amount": 399900,
        "currency": "MXN",
        "type": "DIRECT_DEBIT",
        "status": "INITIATED",
        "description": "Mensualidad",
        "paymentMethodId": "pm_1234567890",
        "customerId": "cus_1234567890",
        "meta": {
            "orderId": "order_1234567890",
            "serviceType": "subscription"
        },
    }
}
Para pagos con domiciliación bancaria, los webhooks son esenciales ya que no obtienes confirmación inmediata. Debes monitorear los eventos PAYMENT_ATTEMPT_SUCCEEDED y PAYMENT_ATTEMPT_FAILED para conocer el resultado final del cargo.

Estados del pago

Después de crear un cargo automático, el pago pasará por diferentes estados:
  • INCOMPLETE: El pago está siendo procesado por el sistema bancario.
  • COMPLETE: El pago se completó exitosamente.
  • INITIATED: El pago ha sido programado y está pendiente de procesamiento.
  • CANCELED: El pago fue cancelado; no se admitirá.

Monitoreo con webhooks

Para mantener tu integración sincronizada con el estado de los pagos, puedes suscribirte a los siguientes webhooks:

Eventos de intentos de pago

  • PAYMENT_ATTEMPT_SUCCEEDED: Se envía cuando un intento de cobro automático es exitoso.
  • PAYMENT_ATTEMPT_FAILED: Se envía cuando un intento de cobro automático falla, incluyendo el código de error correspondiente.

Eventos de métodos de pago

  • PAYMENT_METHOD_CREATED: Se envía cuando un cliente guarda un nuevo método de pago (tarjeta o cuenta bancaria) que podrás usar para cargos automáticos.
Consulta la documentación completa de webhooks para ver todos los eventos disponibles y sus estructuras.
Para casos de uso más complejos con pagos recurrentes programados, considera usar suscripciones con pagos definidos que ofrecen mayor flexibilidad y control.