Lane · Documentación

Guías

Cobro con tarjeta guardada

El cliente autoriza su tarjeta una vez. Después cobras desde tu servidor, sin él.

Las redes distinguen dos situaciones: el cliente está frente a la pantalla, o no está. Los nombres del contrato son initiator: "customer" y initiator: "merchant", y cada uno tiene reglas distintas. Confundirlos es la causa más común de rechazo en un cobro recurrente.

Cliente presenteCliente ausente
initiatorcustomermerchant
CVVObligatorioProhibido — la API lo rechaza
order_typepurchase y los de serieCualquiera menos purchase
Enlace al primer cobroNo aplicaObligatorio en cobros de serie

1. Guarda la tarjeta

Una sesión de inscripción abre una pantalla donde el cliente entrega su tarjeta. No cobra nada: solo la deja autorizada para después.

POST/v1/enrollment/sessions

Crea la pantalla donde el cliente guarda su tarjeta.

Crear la inscripción

curl -X POST https://gxxazsplhgyezwxghrnn.supabase.co/functions/v1/blink-api/v1/enrollment/sessions \
  -H "Authorization: Bearer sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": { "email": "cliente@ejemplo.com" },
    "success_url": "https://mitienda.com/tarjeta-guardada",
    "expires_in": 3600
  }'

Respuesta 201

{
  "id": "7d2b…",
  "object": "enrollment.session",
  "environment": "test",
  "status": "pending",
  "enrollment_url": "https://…"
}

expires_in va entre 60 y 86400 segundos. Cuando el cliente termina, llega el evento instrument.enrolled y la tarjeta aparece en el listado de instrumentos.

2. Encuentra el instrumento

Listar tarjetas guardadas

curl "https://gxxazsplhgyezwxghrnn.supabase.co/functions/v1/blink-api/v1/instruments" \
  -H "Authorization: Bearer sk_test_…"

Respuesta 200

{
  "object": "list",
  "data": [
    {
      "object": "payment.instrument",
      "id": "c1a9f3e0-…",
      "status": "active",
      "customer": { "email": "cliente@ejemplo.com" },
      "bin": "518617",
      "last4": "4242",
      "brand": "MASTERCARD",
      "product": "CREDIT",
      "supports_installments": true,
      "enrolled_at": "2026-09-06T18:20:11.000Z"
    }
  ]
}

3. El primer cobro, con el cliente

El primero de la serie lo inicia el cliente: está mirando la pantalla y escribe su CVV. Ese cobro es el que la red va a usar como referencia de todos los siguientes, así que guarda su identificador.

Primer cobro (CIT)

curl -X POST https://gxxazsplhgyezwxghrnn.supabase.co/functions/v1/blink-api/v1/payments \
  -H "Authorization: Bearer sk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 8900000,
    "currency": "COP",
    "instrument_id": "c1a9f3e0-…",
    "initiator": "customer",
    "cvv": "123",
    "order_type": "recurring"
  }'

4. Los siguientes, sin él

Un cobro de serie sin el cliente presente tiene que apuntar al primero. Manda parent_transaction_data con el first_payment_id que guardaste, o con los datos de red que devolvió aquel cobro. Sin eso la API responde 400, antes de intentar nada.

Cobro recurrente (MIT)

curl -X POST https://gxxazsplhgyezwxghrnn.supabase.co/functions/v1/blink-api/v1/payments \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 8900000,
    "currency": "COP",
    "instrument_id": "c1a9f3e0-…",
    "initiator": "merchant",
    "order_type": "recurring",
    "parent_transaction_data": { "first_payment_id": "9b41d0c7-…" }
  }'
// El día 1 de cada mes, para cada suscripción activa.
async function cobrarMensualidad(sub) {
  const res = await fetch("https://gxxazsplhgyezwxghrnn.supabase.co/functions/v1/blink-api/v1/payments", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.LANE_SECRET_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: sub.montoCentavos,
      currency: "COP",
      instrument_id: sub.instrumentId,
      initiator: "merchant",              // el cliente no está
      order_type: "recurring",
      parent_transaction_data: {
        first_payment_id: sub.primerCobroId,
      },
    }),
  });

  const pago = await res.json();
  if (!res.ok) throw new Error(pago.error);
  return pago;   // status: succeeded | failed | processing
}

Los tipos de orden

`order_type`Para quéQuién lo inicia
purchaseUna compra suelta.Solo el cliente
recurringMensualidad de monto fijo.Ambos
installmentUna compra dividida en pagos.Ambos
standing_orderCobro periódico de monto variable.Ambos
unscheduledRecarga automática, sin fecha fija.Ambos
deferred · delayedCobro que se hace después de la compra.Ambos
no_show · resubmissionPenalidad por no presentarse, reintento de un rechazo.Solo el comercio

Los cobros de serie —recurring, installment, standing_order, deferred, delayed— son los que exigen el enlace al primero. unscheduled, no_show y resubmission no.

Verificar que la tarjeta sigue viva

Antes de un ciclo de cobros puedes preguntar si una tarjeta responde, sin cobrar nada: intent: "account-status" con amount: 0. Al tarjetahabiente no le aparece nada.

Verificación sin cobro

{
  "amount": 0,
  "instrument_id": "c1a9f3e0-…",
  "intent": "account-status",
  "initiator": "customer",
  "cvv": "123"
}
Una tarjeta reemitida deja de servir. Si al cliente le cambian la tarjeta por vencimiento o robo, el instrumento guardado queda muerto y no se actualiza solo. Cuando un cobro recurrente falle por eso, la salida es pedirle al cliente que vuelva a inscribir su tarjeta.

Esta página en markdown: /docs/guias/cobro-recurrente.md · Toda la documentación: /docs/llms-full.txt