Guardar y reutilizar métodos de pago

Usa este flujo cuando necesitas guardar la tarjeta de un cliente y cobrarla después sin que vuelva a ingresar sus datos. Es útil para cobros mensuales de monto variable, cargos por consumo, cargos adicionales a una suscripción o renovaciones administradas por tu sistema.

El cliente siempre ingresa la tarjeta en un checkout alojado por Recurrente. Tu sistema guarda únicamente el payment_method_id retornado por Recurrente y lo usa para crear cobros futuros.

Antes de guardar una tarjeta, asegúrate de que el cliente acepte términos claros sobre cómo se harán los cobros futuros: frecuencia, cómo se calcula el monto, cuándo se cobra y cómo puede cancelar o actualizar su método de pago.

Flujo general

  1. Crea o identifica el cliente en Recurrente.
  2. Crea un checkout con mode: "setup" para tokenizar la tarjeta sin cobrarla.
  3. Envía el checkout_url al cliente.
  4. Cuando el cliente completa el checkout, guarda el payment_method.id.
  5. Usa POST /api/one_time_payments para cobrar ese método guardado cuando tengas el monto final.

Paso 1: Crear o identificar el cliente

Si ya tienes un cliente en Recurrente, usa su customer_id al crear el checkout de tokenización. Si solo tienes el user_id, también puedes enviarlo.

$curl -X POST https://app.recurrente.com/api/customers \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Content-Type: application/json" \
> -d '{
> "email": "cliente@example.com",
> "full_name": "Ana Lopez"
> }'

La respuesta incluye el id del cliente:

1{
2 "id": "cus_abc123",
3 "user_id": "us_123456",
4 "email": "cliente@example.com",
5 "name": "Ana Lopez"
6}

Paso 2: Crear un checkout de tokenización

Crea un checkout con mode: "setup". Este checkout no cobra nada; solo guarda la tarjeta para usos futuros.

$curl -X POST https://app.recurrente.com/api/checkouts \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Content-Type: application/json" \
> -d '{
> "mode": "setup",
> "customer_id": "cus_abc123",
> "success_url": "https://tusitio.com/metodo-guardado",
> "cancel_url": "https://tusitio.com/metodo-cancelado",
> "metadata": {
> "billing_agreement_id": "ba_789"
> }
> }'

Recurrente responde con una URL alojada:

1{
2 "id": "ch_eegw9j5zgqoae3ms",
3 "checkout_url": "https://app.recurrente.com/checkout-session/ch_eegw9j5zgqoae3ms"
4}

Redirige al cliente a checkout_url o envíasela por email, WhatsApp o dentro de tu app.

Paso 3: Guardar el payment_method_id

Cuando el cliente completa el checkout, Recurrente emite setup_intent.succeeded. El método guardado viene dentro de data.checkout.payment_method.

1{
2 "eventType": "setup_intent.succeeded",
3 "eventId": "act_123",
4 "data": {
5 "event_type": "setup_intent.succeeded",
6 "status": "succeeded",
7 "checkout": {
8 "id": "ch_eegw9j5zgqoae3ms",
9 "status": "paid",
10 "payment_method": {
11 "id": "pay_m_7v5ie3pw",
12 "type": "card",
13 "card": {
14 "last4": "4242",
15 "network": "visa"
16 }
17 }
18 },
19 "customer": {
20 "id": "cus_abc123",
21 "email": "cliente@example.com"
22 }
23 }
24}

Guarda data.checkout.payment_method.id. Ese es el token que usarás para cobros futuros.

Si no recibes webhooks, consulta el checkout después de que el cliente vuelva a tu success_url: GET /api/checkouts/{id}. Cuando el checkout está completado, la respuesta incluye payment_method.id.

$curl https://app.recurrente.com/api/checkouts/ch_eegw9j5zgqoae3ms \
> -H "X-SECRET-KEY: tu_llave_secreta"
1{
2 "id": "ch_eegw9j5zgqoae3ms",
3 "status": "paid",
4 "payment_method": {
5 "id": "pay_m_7v5ie3pw",
6 "type": "card",
7 "card": {
8 "last4": "4242",
9 "network": "visa"
10 }
11 }
12}

Paso 4: Cobrar después con un monto variable

Cuando tu sistema sabe el monto a cobrar, crea un pago único con el payment_method_id guardado. Usa una llave de idempotencia única por intento de cobro para evitar duplicados si necesitas reintentar la solicitud.

$curl -X POST https://app.recurrente.com/api/one_time_payments \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Idempotency-Key: invoice-2026-06-cus-abc123" \
> -H "Content-Type: application/json" \
> -d '{
> "payment_method_id": "pay_m_7v5ie3pw",
> "items": [
> {
> "name": "Consumo de junio",
> "amount_in_cents": 87500,
> "currency": "GTQ",
> "quantity": 1
> }
> ]
> }'

Respuesta exitosa:

1{
2 "object": "one_time_payment",
3 "id": "on_123456789",
4 "status": "paid"
5}

Si el banco rechaza el cobro, Recurrente responde con error y no debes reusar la misma Idempotency-Key para un nuevo intento de cobro. Crea un intento nuevo con una llave distinta cuando el cliente confirme que desea reintentar o actualice su método de pago.

Cobros variables asociados a una suscripción

Si el cliente ya tiene una suscripción y quieres agregar cargos variables, tienes dos opciones.

Para cobrar inmediatamente el método guardado de la suscripción:

$curl -X POST https://app.recurrente.com/api/one_time_payments \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Idempotency-Key: su-nehndm7j-extra-junio" \
> -H "Content-Type: application/json" \
> -d '{
> "subscription_id": "su_nehndm7j",
> "amount_in_cents": 5000,
> "description": "Cargo por consumo adicional",
> "mode": "now"
> }'

Para agregar el cargo al próximo ciclo de la suscripción:

$curl -X POST https://app.recurrente.com/api/one_time_payments \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Content-Type: application/json" \
> -d '{
> "subscription_id": "su_nehndm7j",
> "amount_in_cents": 5000,
> "description": "Cargo por consumo adicional",
> "mode": "next_cycle"
> }'

mode: "next_cycle" crea un invoice_item pendiente. También admite montos negativos para créditos.

Actualizar la tarjeta guardada

Cuando el cliente necesite cambiar tarjeta, crea otro checkout mode: "setup". Al completarlo, guarda el nuevo payment_method.id.

Si el método pertenece a una suscripción, actualízala con:

$curl -X PUT https://app.recurrente.com/api/subscriptions/su_nehndm7j \
> -H "X-SECRET-KEY: tu_llave_secreta" \
> -H "Content-Type: application/json" \
> -d '{
> "payment_method_id": "pay_m_nueva123"
> }'

Si solo usas cobros variables con POST /api/one_time_payments, guarda el nuevo payment_method_id en tu sistema y úsalo para los siguientes cobros.

Consideraciones

  • POST /api/one_time_payments requiere que tu cuenta tenga cobros únicos habilitados.
  • El payment_method_id debe pertenecer a un cliente de tu cuenta.
  • Los cobros futuros pueden fallar aunque la tokenización haya sido exitosa. Maneja errores de banco y permite que el cliente actualice su tarjeta.
  • Los webhooks reales solo se envían para eventos de producción. Para validar el flujo completo de tokenización, usa una llave LIVE; el checkout de setup no cobra un monto.
  • Nunca recolectes ni almacenes números de tarjeta directamente. Usa siempre el checkout alojado de Recurrente.