API de Webhooks

Los webhooks permiten que tu aplicación reciba notificaciones HTTP en tiempo real cuando ocurren eventos en tu tienda Mercozy. En lugar de consultar la API, registra una URL y Mercozy enviará automáticamente los datos del evento.

Inicio rápido

Comienza en 3 pasos:

Paso 1: Registra tu endpoint

Obtén tu clave API desde Configuración > Integración > Claves API. Se requiere permiso de administrador. El secreto de firma del webhook (whsec_xxx) se genera automáticamente al crear un endpoint y se muestra solo una vez.

bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks" \
  -H "X-API-Key: mk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My ERP Integration",
    "url": "https://your-app.com/webhooks/mercozy",
    "events": ["order.created", "order.cancelled", "payment.received"]
  }'
Paso 2: Procesa los eventos entrantes
javascript
app.post('/webhooks/mercozy', (req, res) => {
  // 1. Verify signature (see below)
  const signature = req.headers['x-webhook-signature'];
  if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Process the event
  const { type, data } = req.body;
  switch (type) {
    case 'order.created':
      syncOrderToERP(data);
      break;
    case 'payment.received':
      updateAccountingSystem(data);
      break;
  }

  // 3. Respond quickly with 200
  res.status(200).json({ received: true });
});
Paso 3: Prueba tu endpoint
bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks/{id}/test" \
  -H "X-API-Key: mk_live_your_key_here"

Endpoints

GET

/webhooks

webhooks:read

Lista todos los endpoints de webhook registrados.

POST

/webhooks

webhooks:write

Registra un nuevo endpoint de webhook para recibir notificaciones de eventos.

PUT

/webhooks/:id

webhooks:write

Actualiza un endpoint de webhook existente (URL, eventos o estado activo).

DELETE

/webhooks/:id

webhooks:write

Elimina un endpoint de webhook. Los eventos ya no se entregarán.

Referencia de Campos
CampoTipoObligatorioDescripción

id

string

No

Identificador único del webhook (solo lectura)

name

string

Un nombre descriptivo para este endpoint

url

string

URL del endpoint HTTPS para recibir eventos de webhook

events

string[]

Array de tipos de evento a suscribir

secret

string

No

Secreto de firma para verificación de payload (solo lectura, generado al crear)

isActive

boolean

No

Si el webhook está activo (predeterminado: true)

createdAt

datetime

No

Marca de tiempo ISO 8601 (solo lectura)


Tipos de Evento Disponibles

Mercozy admite 18 tipos de eventos de webhook en 6 categorías. Suscríbete solo a los eventos que necesites.

Pedidos
  • order.created

    Se activa cuando se realiza un nuevo pedido

  • order.updated

    Se activa cuando se modifican los detalles del pedido

  • order.cancelled

    Se activa cuando se cancela un pedido

  • order.completed

    Se activa cuando un pedido se marca como completado

  • order.status_changed

    Se activa en cualquier cambio de estado del pedido

Pagos
  • payment.received

    Se activa cuando se captura el pago o se cobra contra reembolso

  • payment.refunded

    Se activa cuando se reembolsa o cancela un pago

Productos
  • product.created

    Se activa cuando se añade un nuevo producto

  • product.updated

    Se activa cuando cambian los detalles del producto

  • product.deleted

    Se activa cuando se elimina un producto

Inventario
  • stock.low

    Se activa cuando el stock baja del umbral

  • stock.updated

    Se activa cuando cambia la cantidad en stock

Clientes
  • customer.created

    Se activa cuando se registra un nuevo cliente

  • customer.updated

    Se activa cuando se actualiza la información del cliente

Entregas
  • delivery.batch_started

    Se activa cuando se despacha un lote de entregas

  • delivery.batch_completed

    Se activa cuando se completan todas las paradas del lote

  • delivery.completed

    Se activa cuando se completa una entrega individual

  • delivery.failed

    Se activa cuando falla un intento de entrega


Payload del Webhook

Cada entrega de webhook incluye el tipo de evento, marca de tiempo y los datos del recurso relevante.

Datos del evento de pedido
json
{
  "id": "evt_clx1abc2def3",
  "type": "order.created",
  "timestamp": "2026-03-19T10:30:00Z",
  "data": {
    "id": "clx9order123",
    "orderNumber": "ORD-1042",
    "status": "PENDING",
    "total": 4999,
    "currency": "USD"
  }
}
Datos del evento de pago
json
{
  "id": "evt_clx2pay4ghi5",
  "type": "payment.received",
  "timestamp": "2026-03-19T10:35:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042",
    "amount": 4999,
    "currency": "USD",
    "paymentMethod": "CARD",
    "status": "CAPTURED"
  }
}
Datos del evento de producto
json
{
  "id": "evt_clx3prod6jkl",
  "type": "product.created",
  "timestamp": "2026-03-19T11:00:00Z",
  "data": {
    "id": "clx9prod789",
    "name": "Organic Coffee Beans",
    "sku": "COF-001",
    "price": 1299,
    "status": "ACTIVE"
  }
}
Datos del evento de entrega
json
{
  "id": "evt_clx4del7mno",
  "type": "delivery.completed",
  "timestamp": "2026-03-19T14:22:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042"
  }
}

Encabezados HTTP

Cada solicitud de webhook incluye los siguientes encabezados:

CampoTipoObligatorioDescripción

Content-Type

string

application/json

X-Webhook-Signature

string

Firma HMAC-SHA256: sha256={resumen_hexadecimal}

X-Webhook-Timestamp

string

Marca de tiempo Unix en milisegundos

X-Webhook-ID

string

ID de evento único para deduplicación

User-Agent

string

Mercozy-Webhook/1.0 (+https://www.mercozy.com/docs/webhooks)


Verificación de Firma

Cada webhook incluye un encabezado X-Webhook-Signature que contiene una firma HMAC-SHA256. Verifica siempre esta firma antes de procesar el evento para asegurar que la solicitud proviene de Mercozy.

Node.js
javascript
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, timestamp, secret) {
  // Signature is computed over "timestamp.body"
  const message = timestamp + '.' + rawBody;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express middleware
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-webhook-signature'];
  const ts = req.headers['x-webhook-timestamp'];
  if (!verifyWebhook(req.body, sig, ts, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // Process event...
  res.status(200).json({ received: true });
});
Python
python
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    # Signature is computed over "timestamp.body"
    message = (timestamp + '.').encode() + payload
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        message,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    sig = request.headers.get('X-Webhook-Signature')
    ts = request.headers.get('X-Webhook-Timestamp')
    if not verify_webhook(request.data, sig, ts, WEBHOOK_SECRET):
        return 'Invalid signature', 401
    event = request.get_json()
    # Process event...
    return {'received': True}, 200
PHP
php
<?php
function verifyWebhook(string $payload, string $signature, string $timestamp, string $secret): bool {
    // Signature is computed over "timestamp.body"
    $message = $timestamp . '.' . $payload;
    $expected = 'sha256=' . hash_hmac('sha256', $message, $secret);
    return hash_equals($expected, $signature);
}

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (!verifyWebhook($payload, $signature, $timestamp, $webhookSecret)) {
    http_response_code(401);
    exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process event...
http_response_code(200);
echo json_encode(['received' => true]);

Política de reintentos

Si tu endpoint devuelve un código de estado no-2xx o se agota el tiempo (10 segundos), Mercozy reintentará la entrega con retroceso exponencial:

CampoTipoObligatorioDescripción

Intento 1

No

Inmediato

Intento 2

No

Después de ~1s

Intento 3

No

Después de ~4s

Tras 3 intentos fallidos, la entrega se marca como fallida. Puedes reintentar manualmente desde el panel o la API.


Mejores prácticas

  • Responde en menos de 5 segundosDevuelve un estado 200 inmediatamente y procesa el evento de forma asíncrona. Mercozy tiene un tiempo de espera de 10 segundos.

  • Verifica siempre las firmasComprueba el encabezado X-Webhook-Signature antes de procesar cualquier evento para evitar solicitudes falsificadas.

  • Maneja duplicados (idempotencia)Usa el encabezado X-Webhook-ID para deduplicar eventos. Almacena los IDs procesados y omite los que ya hayas manejado.

  • Usa endpoints HTTPSMercozy requiere URLs HTTPS en producción para proteger los datos del webhook en tránsito.

  • Registra y monitoreaRegistra todos los webhooks entrantes y monitorea los fallos. Usa la API de registros de entrega para verificar el estado.