Webhooks Personalizados
Conecta Fletea con cualquier sistema que puedas imaginar: tu ERP, CRM, plataforma de e-commerce propia, o cualquier servicio que pueda recibir peticiones HTTP.
Cada vez que cambia el estado de un envio, Fletea envia un POST a tu URL con los datos del evento.

Crear un webhook
Desde el Dashboard
Abre la seccion de webhooks
Ve a Dashboard > Integraciones > Webhooks y haz clic en "Crear Webhook".
Configura los datos
Ingresa un nombre descriptivo (ej: "Mi ERP - Produccion"), la URL HTTPS de tu endpoint y selecciona los eventos que quieres recibir.
Guarda el secret
Al crear el webhook se genera un secret unico. Copialo inmediatamente, lo necesitaras para verificar la autenticidad de los webhooks.
Guardalo en un lugar seguro. Lo necesitaras para verificar la autenticidad de los webhooks que recibas.
Via API
curl -X POST https://app.fletea.mx/api/v1/webhooks \
-H "Authorization: Bearer flt_tu_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Mi ERP - Produccion",
"url": "https://mi-servidor.com/webhooks/fletea",
"events": [
"order.status_changed",
"order.delivered",
"order.failed"
]
}'
Eventos disponibles
| Evento | Descripcion | Cuando se dispara |
|---|---|---|
order.created | Orden creada | Al crear una nueva orden |
order.status_changed | Cambio de estado | Cualquier transicion de estado |
order.picked_up | Recolectado | Paquete recogido por mensajero |
order.in_transit | En transito | Paquete en camino |
order.out_for_delivery | En reparto | Paquete salio a entrega |
order.delivered | Entregado | Entrega exitosa confirmada |
order.failed | Fallido | Intento de entrega fallido |
order.cancelled | Cancelado | Orden cancelada |
Suscribirte a order.status_changed cubre todos los cambios. Si solo necesitas saber cuando se entrega o falla, usa order.delivered y order.failed.
Esquema del payload
Todos los eventos comparten la misma estructura:
{
"id": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event": "order.delivered",
"createdAt": "2026-03-03T14:30:00.000Z",
"data": {
"orderId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"internalReference": "PEDIDO-001",
"status": "delivered",
"providerData": {
"value": "HEX-123456789",
"location": "Monterrey, NL",
"latitud": "25.6866",
"longitud": "-100.3161",
"observations": "Entregado en recepcion",
"dateTimeISO": "2026-03-03T14:30:00Z",
"StatusObj": {
"code": "DLV",
"description": "Entregado"
}
}
}
}
Campos del payload
| Campo | Tipo | Descripcion |
|---|---|---|
id | string | ID unico del evento (UUID v4) |
event | string | Tipo de evento (ej: order.delivered) |
createdAt | string | Fecha ISO 8601 del evento |
data.orderId | string | UUID de la orden en Fletea |
data.internalReference | string | Tu referencia interna |
data.status | string | Nuevo estado de la orden |
data.providerData | object | Datos crudos del proveedor logistico |
Datos del proveedor (providerData)
| Campo | Descripcion |
|---|---|
value | Numero de guia |
location | Ubicacion del evento |
latitud / longitud | Coordenadas GPS (cuando disponibles) |
observations | Notas del proveedor |
dateTimeISO | Fecha del evento del proveedor |
StatusObj.code | Codigo original del proveedor |
StatusObj.description | Descripcion del proveedor |
Verificacion de firma
Cada webhook incluye el header X-Fletea-Signature con una firma HMAC-SHA256. Siempre verifica esta firma antes de procesar.
Node.js
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.FLETEA_WEBHOOK_SECRET;
app.post('/webhooks/fletea', (req, res) => {
// 1. Obtener firma del header
const signature = req.headers['x-fletea-signature'];
if (!signature) {
return res.status(401).json({ error: 'Firma faltante' });
}
// 2. Calcular firma esperada
const body = JSON.stringify(req.body);
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(body)
.digest('hex');
// 3. Comparar de forma segura (timing-safe)
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).json({ error: 'Firma invalida' });
}
// 4. Procesar el evento
const { event, data } = req.body;
switch (event) {
case 'order.delivered':
console.log(`Orden ${data.internalReference} entregada`);
// Actualizar tu sistema...
break;
case 'order.failed':
console.log(`Orden ${data.internalReference} fallida`);
// Notificar a tu equipo...
break;
default:
console.log(`Evento no manejado: ${event}`);
}
res.status(200).json({ received: true });
});
app.listen(3000);
Python (Flask)
import hmac
import hashlib
import json
import os
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = os.environ['FLETEA_WEBHOOK_SECRET']
@app.route('/webhooks/fletea', methods=['POST'])
def handle_webhook():
# 1. Obtener firma del header
signature = request.headers.get('X-Fletea-Signature', '')
if not signature:
return jsonify({'error': 'Firma faltante'}), 401
# 2. Calcular firma esperada
body = request.get_data(as_text=True)
expected = hmac.new(
WEBHOOK_SECRET.encode(),
body.encode(),
hashlib.sha256
).hexdigest()
# 3. Comparar de forma segura
if not hmac.compare_digest(signature, expected):
return jsonify({'error': 'Firma invalida'}), 401
# 4. Procesar el evento
payload = request.get_json()
event = payload['event']
data = payload['data']
if event == 'order.delivered':
print(f"Orden {data['internalReference']} entregada")
# Actualizar tu sistema...
elif event == 'order.failed':
print(f"Orden {data['internalReference']} fallida")
# Notificar a tu equipo...
return jsonify({'received': True}), 200
PHP
<?php
$webhookSecret = $_ENV['FLETEA_WEBHOOK_SECRET'];
$body = file_get_contents('php://input');
// 1. Obtener firma del header
$signature = $_SERVER['HTTP_X_FLETEA_SIGNATURE'] ?? '';
if (empty($signature)) {
http_response_code(401);
echo json_encode(['error' => 'Firma faltante']);
exit;
}
// 2. Calcular firma esperada
$expected = hash_hmac('sha256', $body, $webhookSecret);
// 3. Comparar de forma segura
if (!hash_equals($expected, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Firma invalida']);
exit;
}
// 4. Procesar el evento
$payload = json_decode($body, true);
$event = $payload['event'];
$data = $payload['data'];
switch ($event) {
case 'order.delivered':
error_log("Orden {$data['internalReference']} entregada");
// Actualizar tu sistema...
break;
case 'order.failed':
error_log("Orden {$data['internalReference']} fallida");
// Notificar a tu equipo...
break;
}
http_response_code(200);
echo json_encode(['received' => true]);
Pruebas de webhooks
Con ngrok (desarrollo local)
Instala ngrok
Descarga desde ngrok.com e instalalo.
Inicia tu servidor
Ejecuta tu servidor local en el puerto 3000 (o el que uses).
Crea un tunel
Ejecuta ngrok http 3000 y usa la URL generada (ej: https://abc123.ngrok-free.app/webhooks/fletea) al crear tu webhook en Fletea.
Con webhook.site
Para verificar rapidamente que los webhooks llegan:
- Ve a webhook.site y copia tu URL unica
- Usala como URL del webhook en Fletea
- Crea o actualiza una orden para disparar un evento
- Verifica el payload en webhook.site
Logs de entrega
Puedes consultar el historial completo de cada webhook desde Dashboard > Integraciones > Webhooks:
| Campo | Descripcion |
|---|---|
| Fecha | Cuando se envio el webhook |
| Evento | Tipo de evento disparado |
| Codigo HTTP | Respuesta de tu servidor |
| Tiempo | Duracion de la peticion |
| Reintentos | Numero de intentos realizados |
Politica de reintentos
| Intento | Espera | Timeout |
|---|---|---|
| 1 | Inmediato | 10 segundos |
| 2 | ~1.5 segundos | 10 segundos |
| 3 | ~3 segundos | 10 segundos |
- Los errores
4xxno se reintentan (indican error de configuracion) - Los errores
5xxy timeouts se reintentan hasta 3 veces - Despues de 3 intentos fallidos, el evento se registra como fallido en los logs
Buenas practicas
-
Responde en menos de 10 segundos. Si necesitas procesamiento pesado, guarda el evento en una cola y procesalo despues.
-
Usa idempotencia. El campo
iddel payload es unico. Guardalo para evitar procesar el mismo evento dos veces. -
Verifica siempre la firma. Es tu unica garantia de que el webhook viene de Fletea.
-
Solo HTTPS. No se admiten URLs sin SSL en produccion.
-
Maneja eventos desconocidos. Ignora los eventos que no reconoces con un
200 OK. Fletea puede agregar nuevos tipos de eventos en el futuro.
Si tu webhook falla consistentemente, Fletea puede desactivarlo automaticamente para no saturar tu servidor. Revisa los logs regularmente.