*Workflows › Construir*

# Webhooks entrantes

> Un trigger de webhook da al workflow una dirección privada. Tu sistema hace POST de JSON a ella con un secreto, Filmo responde 202 de inmediato y empieza una ejecución.

## Configúralo

- Elige «Webhook» como trigger. En «Cuerpo», declara el tipo del JSON que vas a enviar.
- En el panel lateral del trigger encontrarás «Endpoint» y «Secreto», cada uno con un botón de copiar. Se muestran en texto claro y existen desde que se crea el workflow.
- Publica el workflow y ponlo «Live». La dirección responde 404 hasta entonces, y vuelve a responder 404 si el workflow se pausa o el trigger se cambia a otro tipo.

## La petición

*Una entrega (datos ficticios)*

```bash
curl -sS -X POST "https://app.filmo.io/api/webhooks/workflows/whk_<token>" \
  -H "X-Webhook-Secret: whsec_<secret>" \
  -H "Idempotency-Key: order-2026-0042-reserved" \
  -H "Content-Type: application/json" \
  -d '{"orderNumber":"P-2026-0042","customerEmail":"ana@example.com"}'
```

- Solo se acepta POST. El token forma parte de la dirección (`whk_` seguido de caracteres aleatorios), y el secreto (`whsec_…`) va en la cabecera `X-Webhook-Secret` o como `Authorization: Bearer <secret>`. Si están los dos, se usa `X-Webhook-Secret`. El secreto es obligatorio en cada llamada. Es un secreto compartido, que se compara en tiempo constante; no es una firma del cuerpo, así que una petición capturada se puede reproducir.
- El cuerpo se interpreta como JSON diga lo que diga `Content-Type`. Envía un objeto JSON (una lista o un texto también funcionan).
- El cuerpo puede ocupar como máximo 256 KiB.
- La dirección del workflow en tu app de Filmo es el host de esa app seguido de `/api/webhooks/workflows/` y el token.

## Respuestas

| Estado | Cuerpo | Cuándo |
| --- | --- | --- |
| 202 | `{ "runId": "…" }` | Se puso en cola un run. |
| 200 | `{ "runId": "…", "duplicate": true }` | Repetiste un `Idempotency-Key` ya visto en este workflow: no hay ejecución nueva, el id de la existente. |
| 400 | `{ "error": "invalid_json" }` | El cuerpo está vacío o no es JSON. |
| 400 | `{ "error": "idempotency_key_too_long" }` | La clave tiene más de 255 caracteres. Se rechaza, no se trunca. |
| 401 | `{ "error": "unauthorized" }` | Falta el secreto o es incorrecto. |
| 404 | `{ "error": "not_found" }` | Token desconocido, el trigger no es un webhook, el workflow no está en Live, o está pausado. Todos dan la misma respuesta a propósito. |
| 409 | `{ "error": "no_version" }` | El workflow nunca se ha publicado. |
| 409 | `{ "error": "conflict" }` | Una carrera poco frecuente con un duplicado cuyo run ha desaparecido. |
| 413 | `{ "error": "body_too_large" }` | Más de 256 KiB. |
| 429 | Un mensaje y `retryAfterMs`, con una cabecera `Retry-After` | Más de unas 60 peticiones en un minuto a esta dirección. El recuento se lleva por instancia de servidor, así que es aproximado. |

Cualquier otro método responde 405.

## El cuerpo se comprueba después del 202

> **Un 202 no significa que el cuerpo fuera válido:** Filmo comprueba el cuerpo contra el tipo que declaraste cuando empieza la ejecución, no cuando llega la petición. Si el cuerpo no coincide, ya has recibido 202 y la ejecución falla con un mensaje como "the webhook body does not match the declared type: …". Quien envía nunca lo sabe. Abre la ejecución en el «Runs» para ver por qué.

Las reglas: los campos adicionales se ignoran; todos los campos que declaraste son obligatorios (declara un campo como Desconocido para aceptar cualquier cosa); un número debe ser un número JSON, no un texto; una fecha debe ser ISO 8601; una enumeración debe ser una de sus opciones. La variable `trigger_body` contiene el cuerpo tal como lo enviaste, incluidos los campos que no declaraste.

## No inicies dos veces la misma ejecución

- Envía una `Idempotency-Key` que identifique lo que ocurrió (un número de pedido y lo que le pasó), no el intento. Una reentrega con la misma clave devuelve 200 y la ejecución original. La clave es única por workflow, no entre workflows.
- Sin la cabecera, no se deduplica nada: dos entregas idénticas inician dos ejecuciones, porque dos cuerpos idénticos pueden ser dos eventos reales. Filmo nunca usa el cuerpo para decidir.
- La protección dura mientras existe la ejecución. Las ejecuciones terminadas se eliminan 90 días después de acabar.

## Las credenciales

- El token y el secreto se crean con el workflow, en todos los workflows, aunque nunca use un webhook. No pertenecen a una versión: no cambian al guardar, publicar, cambiar el trigger ni restaurar nada.
- No hay forma de rotarlos ni regenerarlos. Si se filtra un secreto, el remedio es construir un workflow nuevo, que recibe credenciales nuevas.
- Se muestran a todo el que pueda abrir el workflow en el editor. Para un «Público» workflow significa cualquier miembro de tu empresa. Si no es lo que quieres, cambia el workflow a «Privado»: solo su creador y los administradores pueden abrirlo entonces.

## Qué se ejecuta, y como quién

La ejecución empieza con la versión publicada, se ejecuta con los permisos del creador del workflow y ve el cuerpo en `trigger_body`. La entrega es al menos una vez para los efectos de sus pasos: consulta [Errores y reintentos](https://docs.filmo.io/es/workflows/errors-and-retries#at-least-once).

> **Consejo:** Para verlo de principio a fin, la guía [Iniciar un workflow desde tu propio sistema](https://docs.filmo.io/es/workflows/guides/start-from-your-system) configura un webhook, un tipo y una entrega de prueba.

---

URL canónica: https://docs.filmo.io/es/workflows/incoming-webhooks  
Última actualización: 2026-10-09