Centro de Ayuda de Dardo

Webhooks

Que Dardo le avise a tu sistema cuando pasa algo, en vez de andar preguntando

Un webhook es una dirección tuya —una URL HTTPS de tu servidor— que Dardo llama cuando pasa algo en tu programa de fidelidad. No consultás vos: te avisan.

Cuándo conviene un webhook y cuándo la API

La página principal de la API ya lo adelanta, y vale insistir porque es la decisión que más tiempo ahorra en una integración:

Lo que necesitásLo que corresponde
Reaccionar a algo que pasó en DardoWebhook
Preguntar el estado de una tarjeta ahora mismoAPI (GET /api/v2/cards)
Escribir en Dardo: acreditar, emitir, editarAPI
Enterarte de un cambio "más o menos rápido"Webhook, no un ciclo de consultas

El error más caro de una integración es consultar la API en loop. Si tu sistema pregunta cada 30 segundos por el saldo de mil tarjetas para detectar cambios, estás haciendo miles de pedidos por hora para descubrir que casi nunca pasó nada. Un webhook te avisa una vez, cuando ocurre, y el resto del tiempo tu servidor no hace nada.

Para un punto de venta, los webhooks resuelven el sentido inverso al de acreditar una compra: Dardo → tu sistema. Sirven, por ejemplo, para enterarte de que un cliente instaló su tarjeta y darle el alta en tu CRM, para registrar un escaneo en el salón, o para que la pantalla del cajero muestre que el cliente que está pagando acaba de habilitar un beneficio. Todo eso sin que tu sistema tenga que preguntar nada.

Dar de alta un webhook

Se puede desde el panel, en ConfiguraciónWebhooks, o por API.

POST https://api.dardo.ai/api/v2/webhooks

Cuerpo del pedido

CampoTipoObligatorioQué es
eventsstring[]Nombres de los eventos a los que te suscribís. Ver Nombres de evento.
urlstringNoLa dirección HTTPS tuya que va a recibir las entregas.
curl -X POST 'https://api.dardo.ai/api/v2/webhooks' \
  -H 'X-API-Key: TU_CLAVE_API' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://tu-sistema.com/webhooks/dardo",
    "events": ["CardIssuedEvent"]
  }'

Respuesta

Un 200 con el envelope estándar y, adentro de data, la suscripción creada:

{
  "responseId": "3f1a8b04-6d27-4c9e-9a15-2b8e7c04d913",
  "createdAt": "2026-09-07T18:22:04-03:00",
  "code": 200,
  "data": {
    "id": 1,
    "url": "https://tu-sistema.com/webhooks/dardo",
    "events": ["CardIssuedEvent"]
  }
}

Guardate el data.id: es lo único con lo que después vas a poder dar de baja la suscripción.

El 400 de esta operación tapa dos causas distintas. La especificación declara un solo código de error y lo describe como lista de eventos inválida, o webhooks no disponibles en la suscripción actual. Es decir: el mismo 400 te llega si escribiste mal un nombre de evento y si tu plan no incluye webhooks. Antes de salir a debuggear el nombre, confirmá que estás en plan Business.

Dar de baja un webhook

DELETE https://api.dardo.ai/api/v2/webhooks/{id}

El {id} es el que te devolvió el alta.

curl -X DELETE 'https://api.dardo.ai/api/v2/webhooks/1' \
  -H 'X-API-Key: TU_CLAVE_API'

Responde 200 con el envelope estándar. También acá el único error declarado es un 400, y también tapa dos causas: webhook inexistente, o webhooks no disponibles en la suscripción actual.

Cómo es el cuerpo de cada entrega

Toda entrega llega con la misma forma:

{
  "timestamp": "2026-09-07T18:22:04-03:00",
  "event": "CardIssuedEvent",
  "data": { },
  "is_sandbox": false
}
CampoQué es
timestampCuándo ocurrió el evento.
eventEl nombre del evento, el mismo que pusiste en events al suscribirte.
dataEl contenido, que depende del evento.
is_sandboxSi la entrega corresponde a datos de prueba.

En eventos de nivel agencia, data.id identifica la sub-cuenta a la que se refiere el evento. Si administrás varias cuentas bajo una misma estructura, ese es el campo que te dice de cuál te están hablando.

Nombres de evento

La lista de nombres válidos para events no está en la especificación: se consulta en vivo.

RutaQué devuelve
GET /api/automation/webhooksEl catálogo de nombres de evento aceptados.
GET /api/automation/webhooks/{event}Un ejemplo de payload para ese evento.

Estas dos rutas están referenciadas en la documentación de la operación de alta, pero no figuran como operaciones en la especificación publicada. Por eso no las vas a encontrar en la Referencia ni acá vas a leer un catálogo de eventos: publicar una lista que no podemos verificar sería peor que no publicar ninguna.

Consultá GET /api/automation/webhooks para obtener el catálogo vigente, y usá esos nombres literales en events. Si esa ruta no te responde o querés confirmar qué eventos están activos en tu cuenta, escribinos a soporte@dardo.ai.

Verificar la firma

Esto es lo más importante de la página. Tu endpoint de webhooks es una URL pública: cualquiera que la descubra puede mandarle un JSON inventado. Si le creés sin verificar, le estás dando a un desconocido la capacidad de escribir en tu sistema.

Cada entrega viaja con un header X-Signature:

X-Signature = hash_hmac('sha256', <cuerpo crudo>, <clave API de la cuenta que recibe>)

Es hexadecimal en minúscula, 64 caracteres. Tres reglas que no se negocian:

Calculá el HMAC sobre el cuerpo crudo

Sobre los bytes exactos que recibiste, antes de parsear el JSON y de volver a serializarlo. Si tu framework te entrega el body ya convertido a objeto y lo re-serializás para firmar, el orden de las claves o un espacio de diferencia te van a dar otro hash, y vas a rechazar entregas legítimas. La mayoría de los frameworks tienen una forma de quedarse con el body sin procesar; usala.

Firmá con la clave API de la cuenta que recibe

No con la de quien creó la suscripción. Si administrás varias cuentas, cada entrega se verifica con la clave de la cuenta a la que corresponde el evento.

Cuando una cuenta tiene varias claves API, se firma con la más vieja. Ojo con esto: agregar o rotar claves puede mover la firma a otra clave sin que cambie nada más de tu integración.

Compará con una función de tiempo constante

crypto.timingSafeEqual en Node, hash_equals() en PHP, hmac.compare_digest en Python. Comparar dos hashes con === filtra información sobre cuántos caracteres coincidieron. Es un detalle chico y es gratis hacerlo bien.

Si la cuenta no tiene ninguna clave API, el header X-Signature se omite por completo. No llega vacío ni con un valor por defecto: no llega. Tu código tiene que decidir explícitamente qué hace en ese caso — y lo sano es rechazar la entrega, no procesarla sin verificar. Que una entrega no venga firmada no la vuelve confiable.

Ejemplo en Node.js

Con Express, quedándose con el cuerpo crudo:

import express from 'express';
import crypto from 'node:crypto';

const app = express();
const API_KEY = process.env.DARDO_API_KEY;

// Guardamos el body sin procesar. Sin esto no se puede verificar nada.
app.use('/webhooks/dardo', express.raw({ type: 'application/json' }));

function firmaValida(rawBody, firmaRecibida) {
  if (!firmaRecibida) return false; // header ausente: no confiamos

  const esperada = crypto
    .createHmac('sha256', API_KEY)
    .update(rawBody)          // Buffer crudo, sin re-serializar
    .digest('hex');           // hex minúscula, 64 chars

  const a = Buffer.from(esperada, 'utf8');
  const b = Buffer.from(firmaRecibida, 'utf8');
  if (a.length !== b.length) return false;

  return crypto.timingSafeEqual(a, b);
}

app.post('/webhooks/dardo', (req, res) => {
  if (!firmaValida(req.body, req.get('X-Signature'))) {
    return res.status(401).send('firma inválida');
  }

  const evento = JSON.parse(req.body.toString('utf8'));
  // { timestamp, event, data, is_sandbox }

  // Respondemos primero, procesamos después.
  res.status(200).send('ok');
  encolar(evento);
});

app.listen(3000);

Cómo tiene que comportarse tu receptor

No hay información publicada sobre reintentos, tiempo de espera ni orden de entrega. No podemos decirte cuántas veces se reintenta una entrega fallida, cuánto espera Dardo tu respuesta, ni si dos eventos cercanos llegan en el orden en que ocurrieron. Diseñá asumiendo lo peor: que una entrega puede repetirse y que el orden no está garantizado.

Tres reglas que te cubren igual, y que son buena práctica en cualquier integración por webhooks:

  • Hacé el receptor idempotente. Procesar la misma entrega dos veces tiene que dar el mismo resultado que procesarla una. Guardá una marca de lo ya procesado —el event más el identificador que venga en data— y descartá los repetidos.
  • Respondé rápido y trabajá después. Verificá la firma, encolá el evento, devolvé 200. No hagas la consulta a tu base, el envío del mail y la impresión del ticket dentro del pedido HTTP. Si tardás, arriesgás que la entrega se corte del otro lado.
  • No asumas orden. Si tu lógica depende de que un evento llegue antes que otro, reconstruí el estado consultando la API en vez de encadenar webhooks. El timestamp de cada entrega te dice cuándo ocurrió cada cosa.

Ver también

On this page