API de Webhooks para vendedores
Documentación para integrar los eventos de tu tienda con tu ERP o sistemas externos.
Catálogo de eventos
| Evento | Cuándo se dispara |
|---|---|
suborder.paid | Cuando la suborden de tu tienda pasa a En preparación tras el pago del pedido. |
suborder.shipped | Cuando el envío del paquete es confirmado por el transportista (Sendcloud). |
suborder.delivered | Cuando el transportista confirma la entrega al cliente. |
suborder.cancelled | Cuando la suborden se cancela o se reembolsa (con el motivo y el importe devuelto). |
product.stock_low | Cuando el stock de un producto cae a la altura o por debajo del umbral configurado (máx. 1 aviso por día). |
Ejemplo de payload
suborder.paid
{
"event": "suborder.paid",
"occurredAt": "2026-09-03T10:15:00.000Z",
"storeId": "c6f4af6f-1e2d-4c3b-9a5e-2f7d8e9a1b2c",
"subOrderId": "3a1b7c9d-5e6f-4a8b-8c2d-1e3f4a5b6c7d",
"orderId": "9f8e7d6c-5b4a-49c8-b2d1-0e9f8a7b6c5d",
"status": "PROCESSING",
"amounts": {
"subtotalCents": 11000,
"commissionCents": 1000,
"commissionIvaCents": 210,
"payoutCents": 9790
},
"extra": {
"items": [
{
"productId": "1d2c3b4a-5e6f-47a8-9b0c-1d2e3f4a5b6c",
"quantity": 1
}
]
}
}suborder.shipped
{
"event": "suborder.shipped",
"occurredAt": "2026-09-03T10:15:00.000Z",
"storeId": "c6f4af6f-1e2d-4c3b-9a5e-2f7d8e9a1b2c",
"subOrderId": "3a1b7c9d-5e6f-4a8b-8c2d-1e3f4a5b6c7d",
"orderId": "9f8e7d6c-5b4a-49c8-b2d1-0e9f8a7b6c5d",
"status": "SHIPPED",
"amounts": {
"subtotalCents": 11000,
"commissionCents": 1000,
"commissionIvaCents": 210,
"payoutCents": 9790
},
"extra": {
"trackingUrl": "https://tracking.sendcloud.sc/parcel/abc123"
}
}suborder.delivered
{
"event": "suborder.delivered",
"occurredAt": "2026-09-03T10:15:00.000Z",
"storeId": "c6f4af6f-1e2d-4c3b-9a5e-2f7d8e9a1b2c",
"subOrderId": "3a1b7c9d-5e6f-4a8b-8c2d-1e3f4a5b6c7d",
"orderId": "9f8e7d6c-5b4a-49c8-b2d1-0e9f8a7b6c5d",
"status": "DELIVERED",
"amounts": {
"subtotalCents": 11000,
"commissionCents": 1000,
"commissionIvaCents": 210,
"payoutCents": 9790
},
"extra": {
"deliveredAt": "2026-09-04T09:30:00.000Z"
}
}suborder.cancelled
{
"event": "suborder.cancelled",
"occurredAt": "2026-09-03T10:15:00.000Z",
"storeId": "c6f4af6f-1e2d-4c3b-9a5e-2f7d8e9a1b2c",
"subOrderId": "3a1b7c9d-5e6f-4a8b-8c2d-1e3f4a5b6c7d",
"orderId": "9f8e7d6c-5b4a-49c8-b2d1-0e9f8a7b6c5d",
"status": "REFUNDED",
"amounts": {
"subtotalCents": 11000,
"commissionCents": 1000,
"commissionIvaCents": 210,
"payoutCents": 9790
},
"extra": {
"kind": "refunded",
"refundAmountCents": 11000
}
}product.stock_low
{
"event": "product.stock_low",
"occurredAt": "2026-09-03T02:00:00.000Z",
"storeId": "c6f4af6f-1e2d-4c3b-9a5e-2f7d8e9a1b2c",
"productId": "1d2c3b4a-5e6f-47a8-9b0c-1d2e3f4a5b6c",
"productName": "Sobrasada de Mallorca",
"stock": 2,
"threshold": 3,
"dedupKey": "stock-low:1d2c3b4a-5e6f-47a8-9b0c-1d2e3f4a5b6c:2026-09-03"
}Verificación de la firma (HMAC-SHA256)
Cada entrega incluye la cabecera X-Webhook-Signature: el HMAC-SHA256 (hex) del cuerpo crudo de la petición, calculado con tu clave secreta de endpoint. Verifica siempre la firma antes de procesar el payload.
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody = the RAW request body string (before JSON.parse)
const expected = createHmac('sha256', WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
const received = req.headers['x-webhook-signature'] ?? '';
const valid =
received.length === expected.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(received));
if (!valid) return res.status(400).end();PHP
<?php
// $rawBody = file_get_contents('php://input') (raw, not decoded)
$expected = hash_hmac('sha256', $rawBody, $secret);
$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(400);
exit;
}Reintentos
Si tu endpoint no responde con un 2xx, reintentamos hasta 5 intentos por entrega con el siguiente esquema:
| Intento | Espera antes del reintento |
|---|---|
| 1 | Inmediato |
| 2 | 300s (0 h) |
| 3 | 1800s (1 h) |
| 4 | 7200s (2 h) |
| 5 | 21600s (6 h) |
Tras el 5.º intento fallido el evento queda marcado como fallido y recibirás un aviso por email. Reparado el endpoint, los eventos nuevos vuelven a entregarse con normalidad.