n1coePayDocs Referencia del API

Guardar una tarjeta

Guarda la tarjeta de un comprador con una sesión de tarjeta y el card element de n1co.js, sin que los datos pasen por tu página.

  1. Tu servidor crea una sesión de tarjeta con POST /v1/card_sessions y entrega su client_secret a la página.
  2. Tu página muestra el card element y llama a capture({ client_secret }).
  3. Tu servidor confirma la tarjeta con la sesión o con el webhook card.created.

Primero, tu servidor crea la sesión:

Crear una sesión de tarjeta
curl -s -X POST https://api-epay.dev.n1co.dev/v1/card_sessions \
  -H "Authorization: Bearer $N1CO_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "customer": {
      "id": "cust-1001",
      "name": "Ana López",
      "email": "ana.lopez@example.com",
      "phone": "+503 7000-1234"
    },
    "page_origins": ["https://shop.example.com"]
  }'
201 Created
{
  "id": "cs_U2Vzc2lvbkV4YW1wbGUwMDAx",
  "client_secret": "cs_U2Vzc2lvbkV4YW1wbGUwMDAx_secret_U2VjcmV0RXhhbXBsZTAwMDAwMDAwMDAw",
  "status": "requires_card",
  "attempts_remaining": 5,
  "card": null,
  "page_origins": ["https://shop.example.com"],
  "expires_at": "2026-10-16T15:19:05Z",
  "created_at": "2026-10-16T15:04:05Z"
}

Luego, la página. Cambia la llave pública por la tuya y apunta los dos fetch a tus endpoints:

guardar-tarjeta.html
<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Guardar tarjeta</title>
  </head>
  <body>
    <form id="card-form">
      <div id="card"></div>
      <p id="card-message" role="alert"></p>
      <button id="save" type="submit" disabled>Guardar tarjeta</button>
    </form>

    <script src="https://elements.n1co.dev/v1/n1co.js"></script>
    <script>
      const card = n1co('pk_3x4mpl3pUbl1shabl3k3yAAAAAAAAAAA').elements().create('card', { locale: 'es' });
      const save = document.querySelector('#save');
      const message = document.querySelector('#card-message');

      card
        .on('change', ({ complete, error }) => {
          save.disabled = !complete;
          message.textContent = error ? error.message : '';
        })
        .on('error', (error) => {
          message.textContent = error.message;
        })
        .mount('#card');

      document.querySelector('#card-form').addEventListener('submit', async (event) => {
        event.preventDefault();
        save.disabled = true;
        try {
          // Tu endpoint crea la sesión con tu llave secreta y devuelve solo su client_secret.
          const { client_secret } = await fetch('/checkout/card-session', { method: 'POST' }).then((r) => r.json());
          const result = await card.capture({ client_secret });
          // Tu servidor confirma leyendo la sesión con la llave secreta.
          await fetch('/checkout/card', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ card: result.card.id }),
          });
          message.textContent = `Guardamos tu tarjeta terminada en ${result.card.last4}.`;
        } catch (error) {
          message.textContent = error.message;
          save.disabled = false;
        }
      });
    </script>
  </body>
</html>

La página se sirve por https. Para desarrollar también se aceptan http://localhost y http://127.0.0.1.

El cliente viaja en la solicitud#

customer es un objeto con tu propio id del comprador, su nombre, su correo y su teléfono. No hay que crear el cliente antes: el API lo crea la primera vez que ve ese id y, en los llamados siguientes, actualiza los demás datos.

Campo Reglas
id Tu identificador: de 1 a 64 caracteres A-Z a-z 0-9 . _ -.
name De 2 a 100 caracteres.
email Un correo válido.
phone Formato E.164. Se aceptan espacios, guiones y paréntesis.

Los cuatro son requeridos. Ninguna respuesta ni webhook devuelve el cliente.

La sesión#

El client_secret se muestra solo al crear la sesión. Sirve para una tarjeta, durante 15 minutos y 5 intentos.

Con page_origins, la sesión solo funciona en esas páginas: de 1 a 5 orígenes como https://shop.example.com. Úsalo siempre en producción.

status Significado
requires_card Esperando una tarjeta.
completed Se guardó una tarjeta; card tiene su id.
expired Venció sin una tarjeta.
canceled Sin intentos, o la captura no se pudo confirmar.

Lo que tu página debe manejar#

capture() se resuelve con { ok: true, card }: el id de la tarjeta, la marca, los últimos cuatro dígitos y el vencimiento. Si falla, se rechaza con un code estable y un message listo para mostrar.

  • Un campo inválido: muestra message; el comprador lo corrige.
  • card_rejected: pide otra tarjeta.
  • La sesión ya no sirve (card_session_expired, card_session_canceled y similares): crea una sesión nueva.
  • capture_timeout o network_error: la tarjeta pudo guardarse. Lee la sesión en tu servidor antes de reintentar.

Todos los códigos, opciones y eventos del card element están en la referencia de n1co.js.

Confirmar en tu servidor#

El resultado del navegador es una pista. Tu servidor confirma con GET /v1/card_sessions/{id}: la sesión está completed y card es el id de la tarjeta.

curl -s https://api-epay.dev.n1co.dev/v1/card_sessions/cs_U2Vzc2lvbkV4YW1wbGUwMDAx \
  -H "Authorization: Bearer $N1CO_SECRET_KEY"

También recibes el webhook card.created con la tarjeta. Su card_session es el id de la sesión (cs_…), que la une al comprador para el que creaste la sesión:

card.created
{
  "id": "evt_RXZlbnRFeGFtcGxlMDAwMDAx",
  "type": "card.created",
  "created_at": "2026-10-16T15:06:12Z",
  "data": {
    "object": {
      "id": "card_Q2FyZEV4YW1wbGUwMDAwMDAx",
      "card_session": "cs_U2Vzc2lvbkV4YW1wbGUwMDAx",
      "brand": "visa",
      "last4": "4242",
      "exp_month": 12,
      "exp_year": 2030,
      "issuer": { "name": "Banco Ejemplo", "country": "SV" },
      "fingerprint": "5f0c3b1e9a7d4c2b8e6f0a1d3c5b7e9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b",
      "status": "active",
      "created_at": "2026-10-16T15:06:12Z"
    }
  }
}

Guarda el id de la tarjeta junto a tu usuario: con él y el mismo customer.id cobras la tarjeta después. Si el comprador guarda una tarjeta que ya tenía, recibes el mismo id y no llega otro card.created.

Tarjetas que dejan de servir#

Una tarjeta active se puede cobrar. Pasa a unavailable cuando n1co deja de conocerla, y vuelve a active si el comprador la guarda de nuevo.

Al cobrar, el API rechaza una tarjeta unavailable con 409 card_unavailable: pide al comprador que la escriba otra vez. Los campos de la tarjeta están en la referencia del API.