Skip to content

Links de Colección (API)

Los links de colección son páginas alojadas por Zelta Pay que capturan la tarjeta del cliente, la tokenizan con el procesador activo de la cuenta (NMI o Emetec) y crean un cliente vaulteado. Son el punto de entrada del flujo de integración: una vez capturada la tarjeta, tu software mueve el dinero por API.

Existen dos variantes:

  • Link de colección (POST /v1/collections/links): solo captura y vaultea la tarjeta y crea el cliente. No cobra nada.
  • Link de pago de cliente (POST /v1/collections/payment-links): cobra un amount y vaultea la tarjeta en el mismo checkout; requiere un productCode.

Ambas variantes son solo tarjeta — Yappy no puede almacenar una credencial. Todos los endpoints requieren tu API key de proyecto en el header X-API-Key.

Crea una página alojada que únicamente recolecta la tarjeta: se tokeniza con el procesador activo de tu cuenta (NMI o Emetec) y se crea un cliente. Sin producto, sin monto, sin cobro.

http
POST /v1/collections/links

Cuerpo de la solicitud:

CampoTipoRequeridoDescripción
customer.namestringNombre del cliente (1-120 caracteres)
customer.emailstringNoCorreo del cliente
isTestbooleanNoEntorno sandbox (por defecto false)
redirectUrlstringNoURL a la que redirigir al cliente tras una captura exitosa
metadataobjectNoSe devuelve en el webhook customer.created
bash
curl -X POST https://api-pay.zelta.dev/v1/collections/links \
  -H "X-API-Key: tu-api-key-de-proyecto" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": { "name": "John Doe", "email": "john@example.com" },
    "redirectUrl": "https://tu-app.com/billing/payment-method-saved",
    "metadata": { "userId": "usr_123" }
  }'

Respuesta (201):

json
{
  "success": true,
  "data": {
    "id": "1234567890",
    "paymentLinkUrl": "https://pay.zelta.dev/AbCdEf123",
    "hashUrl": "AbCdEf123",
    "customerName": "John Doe",
    "customerEmail": "john@example.com",
    "status": "pending",
    "isTest": false,
    "expiresAt": "2026-06-11T00:00:00.000Z",
    "createdAt": "2026-06-04T00:00:00.000Z",
    "redirectUrl": "https://tu-app.com/billing/payment-method-saved"
  },
  "message": "Customer collection link created"
}

Envía al cliente a paymentLinkUrl. Cuando guarde su tarjeta recibirás el webhook en el webhook del proyecto — guarda customer.id y los metadatos de la tarjeta, y luego mueve las transacciones por API.

Igual que un link de colección, pero la página alojada cobra amount en el mismo checkout en que almacena la tarjeta y crea el cliente. Úsalo para un primer pago que además inscribe al cliente para cobros futuros (p. ej. una compra inicial + una tarjeta guardada para una suscripción). Solo tarjeta — Yappy no puede almacenar una credencial.

http
POST /v1/collections/payment-links

Cuerpo de la solicitud:

CampoTipoRequeridoDescripción
customer.namestringNombre del cliente (1-120 caracteres)
customer.emailstringNoCorreo del cliente
conceptstringQué se está pagando (se muestra en el checkout)
amountintegerMonto en centavos (100–1,000,000, es decir $1–$10,000)
productCodestringCódigo de un producto one_time del proyecto. El pago liquidado se registra como un cargo de este producto contra el nuevo cliente y se emite un webhook charge.succeeded (después de customer.created)
isTestbooleanNoEntorno sandbox (por defecto false)
redirectUrlstringNoURL a la que redirigir al cliente tras un pago exitoso
metadataobjectNoSe devuelve en los webhooks payment.success y customer.created
bash
curl -X POST https://api-pay.zelta.dev/v1/collections/payment-links \
  -H "X-API-Key: tu-api-key-de-proyecto" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": { "name": "John Doe", "email": "john@example.com" },
    "concept": "Plan Pro — primer mes",
    "amount": 2999,
    "productCode": "activacion",
    "redirectUrl": "https://tu-app.com/billing/welcome",
    "metadata": { "userId": "usr_123" }
  }'

Respuesta (201):

json
{
  "success": true,
  "data": {
    "id": "1234567890",
    "paymentLinkUrl": "https://pay.zelta.dev/AbCdEf123",
    "hashUrl": "AbCdEf123",
    "customerName": "John Doe",
    "customerEmail": "john@example.com",
    "concept": "Plan Pro — primer mes",
    "amount": 2999,
    "status": "pending",
    "isTest": false,
    "expiresAt": "2026-06-11T00:00:00.000Z",
    "createdAt": "2026-06-04T00:00:00.000Z",
    "redirectUrl": "https://tu-app.com/billing/welcome"
  },
  "message": "Customer payment link created"
}

Envía al cliente a paymentLinkUrl. En un checkout exitoso recibirás ambos webhooks: (por el cargo) y (con customer.id y los metadatos de la tarjeta almacenada) — guarda el cliente y luego mueve más cargos/suscripciones por API. Si el pago es rechazado no se crea ningún cliente.

El pago liquidado se registra como un cargo de productCode contra el nuevo cliente (aparece en GET /v1/charges y en la vista de cargos del proyecto) y se emite además un webhook charge.succeeded después de customer.created, con la misma forma que un cargo movido por API — de modo que el primer pago se reconcilia por el mismo camino que tus llamadas posteriores a POST /v1/charges.

Un link alojado es una URL normal, así que una página no puede forzarse a abrirse como popup — la ventana la abre tu código. Para mantener al cliente en tu sitio (estilo PayPal), abre paymentLinkUrl con window.open en lugar de navegar fuera. La página alojada detecta que fue abierta de esta forma (window.opener) y, al tener éxito, publica un mensaje a tu página y se cierra sola.

js
function openZeltaCheckout(paymentLinkUrl, onDone) {
  const w = 480;
  const h = 720;
  const left = window.screenX + (window.outerWidth - w) / 2;
  const top = window.screenY + (window.outerHeight - h) / 2;
  const popup = window.open(
    paymentLinkUrl,
    "zeltapay-checkout",
    `width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`,
  );

  function handleMessage(event) {
    // Solo confía en mensajes de la página alojada de ZeltaPay.
    if (event.origin !== "https://pay.zelta.dev") return;
    const { type } = event.data || {};
    if (type === "zeltapay:collected" || type === "zeltapay:paid") {
      window.removeEventListener("message", handleMessage);
      popup?.close();
      onDone(event.data);
    }
  }

  window.addEventListener("message", handleMessage);
}

El mensaje publicado es solo para mostrar (nunca contiene ningún secreto):

json
{
  "type": "zeltapay:collected",
  "status": "collected",
  "orderId": null,
  "customerEmail": "john@example.com",
  "card": { "brand": "visa", "last4": "4242" }
}

type es zeltapay:collected para un link de colección y zeltapay:paid para un link de pago de cliente. Si el popup se bloquea o se abre como pestaña normal, la página recurre a redirigir a redirectUrl.

El webhook es la fuente de verdad

El mensaje de postMessage es solo una señal de UI para cerrar la ventana y refrescar. El webhook sigue siendo la fuente de verdad: confirma el resultado desde los webhooks customer.created / payment.success, no desde el mensaje de la ventana.

Siguientes pasos

  • — consulta el cliente creado tras la captura
  • — cobra al cliente vaulteado
  • — suscribe al cliente a un plan recurrente
  • customer.created y payment.success

Documentación oficial de Zelta