Hosted Checkout

Escuchar webhooks

Qué webhooks envía un pago de Hosted Checkout, y un handler que confirma el pedido de forma segura.

Los webhooks son la forma más fiable de conocer el resultado de un pago. En lugar de consultar la API repetidamente, Tonder envía un HTTP POST a tu servidor cada vez que el pago cambia de estado.

Qué webhooks recibes

Hosted Checkout 2.0 procesa los pagos con la API Direct, así que recibes los webhooks de pago estándar de Tonder: los mismos que se describen en Cómo funcionan los webhooks. El evento llega en event_type:

event_typeSignificado
payment_PendingEl pago se inició y está en proceso (un desafío 3D Secure, un voucher o una transferencia en espera de pago).
payment_SuccessEl pago se completó con éxito.
payment_FailedEl pago falló.

Los payloads y la lista completa están en el Catálogo de eventos.

No hay webhooks a nivel de sesión: session.created, session.completed y session.expired no se envían. Para seguir una sesión, usa los webhooks de pago, los eventos del checkout embebido o Consultar una sesión. Las sesiones de registro de tarjeta no crean ningún pago, así que no envían ningún webhook.

Qué webhooks recibes se define por cuenta. Si tu cuenta todavía opera con el flujo legacy, recibes los payloads descritos en Webhooks legacy. ¿No sabes cuál te aplica? Consúltalo con soporte de Tonder.

Prerrequisitos

Necesitas una URL pública en tu servidor —por ejemplo https://your-store.com/webhooks/tonder— que pueda recibir peticiones POST. No puede ser una URL de localhost.

Configurar y escuchar

  1. Inicia sesión en el Dashboard: dashboard-stage.tonder.io (Sandbox) o dashboard.tonder.io (Producción).
  2. Ve a Developers → Webhooks.
  3. Haz clic en Crear endpoint, pega la URL pública de tu endpoint y selecciona los eventos de pago (Endpoints explica cada campo).
  4. Haz clic en Crear y guarda el secreto de firma que se muestra. Registra un endpoint en cada entorno. En cuentas sin Webhooks 2.0 el botón dice Add Endpoint y la URL recibe todos los eventos.

Crea la sesión con tu referencia del pedido dentro de metadata (metadata.external_id). Regresa en cada webhook, y es la llave con la que concilias. Consulta Claves de correlación.

Verifica la firma y responde 200 OK de inmediato, antes de ejecutar lógica de negocio —en menos de 10 segundos. Con Webhooks 2.0 una entrega que no recibe un 2xx se reintenta automáticamente (ver Entrega y reintentos); sin él, cada evento se entrega una sola vez y una entrega fallida no se reenvía.

const express = require('express');
const { Webhook } = require('standardwebhooks');

const app = express();
const wh = new Webhook(process.env.TONDER_WEBHOOK_SECRET); // "whsec_...", solo en el servidor

app.post('/webhooks/tonder', express.raw({ type: 'application/json' }), (req, res) => {
  let event;
  try {
    // 1. Verifica la firma sobre el cuerpo crudo
    event = wh.verify(req.body, req.headers);
  } catch {
    return res.sendStatus(400);
  }

  // 2. Confirma la recepción de inmediato
  res.sendStatus(200);

  // 3. Procesa el evento — una vez por webhook-id (req.headers['webhook-id'])
  const orderId = event.metadata && event.metadata.external_id;
  switch (event.event_type) {
    case 'payment_Success':
      // TODO: confirma del lado del servidor y después entrega el pedido `orderId`.
      break;
    case 'payment_Failed':
      // El cliente puede reintentar en la misma sesión; no canceles el pedido todavía.
      break;
    case 'payment_Pending':
      // En espera de 3D Secure, del pago de un voucher o de una transferencia.
      break;
    default:
      // endpoint.test y eventos que no manejas: nada que hacer
  }
});

app.listen(3000, () => console.log('Escuchando webhooks en el puerto 3000'));

Sin Webhooks 2.0 los webhooks no vienen firmados: revisa el header de autenticación que configuraste en lugar de llamar a verify. Detalles en Verifica la firma.

No confíes únicamente en el payload. Antes de entregar el pedido, consulta la sesión o el pago en la API; ve Consultar el estado.

Un cliente puede reintentar dentro de una misma sesión, así que puedes recibir un intento fallido seguido de uno exitoso para el mismo pedido. Procesa los webhooks de forma idempotente y trata payment_Success como el único evento que completa el pedido. Consulta Entrega.

Siguientes pasos

¿Te resultó útil esta página?

En esta página