Pulsa / para buscar

Toda la documentación
docs Vigilar y actuar Automatizaciones y webhooks

Se ejecuta enWrit CloudAutoalojado

Referencia y guía

Automatizaciones y webhooks

Una automatización conecta un evento con una acción: un cambio detectado, un webhook entrante, una programación o un evento de ejecución dispara una regla, sus condiciones se comprueban y sus acciones se ejecutan. Los webhooks llevan eventos hacia dentro y resultados hacia fuera — firmados en ambos sentidos.

Triggers, condiciones, acciones

Una automatización se compone de bloques: un trigger (el evento que la dispara), condiciones opcionales y una o varias acciones. Los triggers disparan con estos tipos de evento — change_detected es el predeterminado:

Tipo de eventoDispara cuando
change_detectedUna comprobación de monitor encuentra un cambio real frente a su referencia.
webhook_receivedUn sistema externo llama a tu hook entrante o a una puerta custom_path.
ai_session_started / ai_session_completedUna AI session empieza o se resuelve.
workflow_started / workflow_completedUna ejecución de workflow empieza o se resuelve.
monitor_down / monitor_stale / monitor_recoveredUn monitor deja de responder, deja de informar, o vuelve.
crawl_started / crawl_completed / crawl_failedUn crawl empieza, termina o falla.
scheduledUn bloque de programación en la raíz de la automatización dispara a su hora.

Las acciones son notification, ai_session, workflow, crawl o create_persona — más return_data en forma de bloque para responder a un llamador síncrono. Cuando varias reglas coinciden, la prioridad es el orden de ejecución. Las condiciones usan los mismos once operadores, el mismo contexto de plantilla y los mismos filtros documentados en monitores.

Writ se ejecuta en tus propias cuentas, con tus propias credenciales y datos, en los sitios que estás autorizado a usar.

Webhooks entrantes (firmados)

Cada hook entrante tiene un secreto de firma, asignado al crearlo — no puede borrarse, y las llamadas sin firma se rechazan. La firma es un HMAC-SHA256, en hexadecimal, sobre "{timestamp}." + cuerpo en bruto:

POST /api/webhooks/hook/{token}
Content-Type: application/json
X-Writ-Timestamp: 1718980000
X-Writ-Signature: sha256=<hex>

{ "sku": "SKU-123" }
  • X-Writ-Timestamp es obligatorio; ausente, inválido o con más de 300 segundos, la respuesta es 401.
  • La misma firma vista de nuevo dentro de 300 segundos se rechaza con 403 — una llamada capturada no puede repetirse.
  • Se acepta un encabezado X-Hub-Signature-256 al estilo GitHub como alternativa a X-Writ-Signature.
  • Cada token de hook está limitado a 30 llamadas por 60 segundos; más allá, la respuesta es 429.

Puertas custom_path

Un trigger de webhook también puede reclamar un custom_path — una ruta legible de hasta 100 caracteres, única en tu espacio de trabajo — servida en una URL estable y autenticada con una clave API en lugar de una firma por llamada:

POST /api/v1/webhooks/{custom_path}?wait=true&timeout=120
Authorization: Bearer wt_xxxxxxxxxxxx
Content-Type: application/json

{ "sku": "SKU-123" }
  • Authorization: Bearer con una clave API es obligatorio — sin clave válida, la respuesta es 401. La ruta se resuelve dentro del espacio de trabajo de la clave llamante.
  • La action de la puerta es run_workflow (predeterminada) o check_target.
  • Una puerta run_workflow cuenta contra el cupo de endpoints publicados de tu plan.
  • Llamadas síncronas: fija wait_for_result en el trigger (false por defecto) con wait_timeout de 10 a 300 segundos (120 por defecto) — o sobreescribe por llamada con ?wait= y ?timeout=.

Entregas salientes

El canal de notificación webhook publica los resultados en tu endpoint, firmados para que puedas verificarlos. Las entregas se comportan de forma previsible:

  • Solo POST o PUT, con User-Agent: Writ-Webhook/1.0 y X-Writ-Timestamp en cada petición.
  • Verifica X-Writ-Signature-V1: cubre "{timestamp}." + el cuerpo en bruto, el mismo material que firma una llamada entrante, así que una sola receta sirve para ambas direcciones y una entrega capturada caduca con su marca de tiempo.
  • X-Writ-Signature viaja al lado y cubre solo el cuerpo JSON. Existe para que los handlers escritos antes de V1 sigan funcionando — no lo uses en código nuevo.
  • Las redirecciones nunca se siguen, y las entregas a destinos de red privada se rechazan — un destino rechazado no se reintenta.
  • Hasta 3 intentos, con 30 segundos de plazo cada uno y backoff exponencial con tope de 30 segundos.

Qué sigue

  • Monitores: el pipeline de triggers, los operadores de condición y los filtros de plantilla.
  • Workflows: qué ejecuta una acción run_workflow.
  • Managed endpoints: el cupo de endpoints publicados que comparten las puertas custom_path.

Dos direcciones, dos firmas

Los webhooks fluyen en ambos sentidos: un sistema externo puede iniciar una automatización de Writ, y Writ puede hacer POST a tu endpoint. Ambas direcciones van firmadas con HMAC — pero firman material distinto, así que verifica cada una como corresponde.

Entrante — tú llamas a Writ

POST a tu URL de hook con un encabezado de marca de tiempo y una firma sobre "{timestamp}." + el cuerpo en bruto. La marca de tiempo debe ser fresca (dentro de 300 segundos) y una firma repetida se rechaza como repetición.

Saliente — Writ te llama

Writ entrega un payload JSON con una firma sobre el cuerpo únicamente. La marca de tiempo viaja como encabezado junto a la firma, no dentro del MAC.

Firmar una llamada de trigger entrante

Calcula un HMAC-SHA256 con el secreto del hook sobre "{timestamp}." + body, codifícalo en hexadecimal y envía ambos encabezados. La firma es obligatoria — las llamadas sin firma se rechazan, y el secreto se asigna con el hook y no puede desactivarse. Se acepta como alternativa un encabezado X-Hub-Signature-256 al estilo GitHub.

send.py

import hashlib, hmac, json, os, time
import requests

secret = os.environ["WEBHOOK_SECRET"]        # shown when the inbound hook is created
body = json.dumps({"sku": "SKU-123"})
ts = str(int(time.time()))
sig = hmac.new(secret.encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()

requests.post(
    "https://api.usewrit.app/api/webhooks/hook/{token}",
    data=body,
    headers={
        "Content-Type": "application/json",
        "X-Writ-Timestamp": ts,
        "X-Writ-Signature": f"sha256={sig}",
    },
    timeout=30,
)

Verificar una entrega saliente

Toma X-Writ-Signature-V1, quita el prefijo sha256=, recalcula un HMAC-SHA256 sobre "{timestamp}." + el cuerpo en bruto con el secreto de tu endpoint, y compara en tiempo constante. El antiguo X-Writ-Signature cubre solo el cuerpo y se sigue enviando para handlers escritos antes de V1 — el código nuevo debe verificar V1.

verify.py

import hashlib, hmac, os

def verify(raw_body: bytes, signature: str) -> bool:
    secret = os.environ["WRIT_WEBHOOK_SECRET"].encode()
    expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    # Constant-time compare - never use ==
    return hmac.compare_digest(expected, signature)

Verifica siempre antes de actuar. Usa el cuerpo en bruto, sin parsear — parsearlo y volver a serializarlo cambia los bytes y rompe la firma. Comprueba la frescura de X-Writ-Timestamp y descarta payloads ya procesados.

Cómo es una entrega

Una entrega change_detected lleva el evento, una marca de tiempo, el target, el selector que cambió y el contenido antes/después con sus huellas. Las entregas salen como POST o PUT, con User-Agent Writ-Webhook/1.0, y las redirecciones nunca se siguen.

POST /your/webhook/handler HTTP/1.1
Content-Type: application/json
User-Agent: Writ-Webhook/1.0
X-Writ-Timestamp: 1718980000
X-Writ-Signature-V1: sha256=6b3a9c…
X-Writ-Signature: sha256=9f86d0…

{
  "event": "change_detected",
  "timestamp": "2026-08-03T14:02:11Z",
  "target": { "id": 42, "url": "https://example.com/pricing", "name": "Pricing page" },
  "selector": { "css": ".price", "name": "price" },
  "change": {
    "content_before": "$129",
    "content_after": "$119",
    "content_hash": "…",
    "previous_hash": "…"
  }
}

Qué dispara una automatización

Webhook entrante

Un sistema externo hace POST a tu URL de hook firmada — o a una puerta custom_path autenticada con Bearer.

Cambio detectado

Una comprobación de monitor encuentra un cambio real frente a su referencia y el pipeline de triggers despacha la automatización.

Eventos de ejecución

Eventos de ciclo de vida de workflows, AI sessions y crawls — iniciado, completado, fallido — y transiciones de salud de los monitores.

Consulta el modelo completo de triggers y acciones en automations y el patrón watch-and-act en monitores.

FAQ de webhooks

¿Cómo se autentican las entregas salientes?
Cada entrega lleva X-Writ-Signature-V1: sha256=<hex> — un HMAC-SHA256 sobre "{timestamp}." + el cuerpo JSON en bruto con el secreto de tu endpoint. Quita el prefijo sha256=, recalcula sobre los bytes en bruto y compara en tiempo constante. Rechaza lo que no coincida. Un X-Writ-Signature sobre solo el cuerpo viaja al lado, para handlers escritos antes de V1.
¿Cómo se evitan las repeticiones en llamadas entrantes?
El encabezado X-Writ-Timestamp es obligatorio y debe estar dentro de 300 segundos — una marca ausente, inválida o caducada recibe 401. La misma firma vista de nuevo dentro de 300 segundos se rechaza con 403. Cada token de hook está además limitado a 30 llamadas por 60 segundos (429 más allá).
¿Qué encabezado de firma saliente debo verificar?
X-Writ-Signature-V1. Ata la marca de tiempo al MAC, así que una entrega capturada ya no se puede repetir en cuanto X-Writ-Timestamp caduca, y firma exactamente el mismo material que una llamada entrante — una sola receta para ambas direcciones. X-Writ-Signature cubre solo el cuerpo y se conserva únicamente para handlers escritos antes de V1.
¿Dónde se ejecuta el workflow disparado?
En tu propio agente local o BYO sin cargo de cómputo, o en el cloud gestionado medido por tiempo de ejecución. Writ se ejecuta en tus propias cuentas, con tus propias credenciales y datos, en sitios que estás autorizado a usar.