Webhook: qué es y cómo conectar la IA con formularios y hojas
Aprende qué es un webhook en la práctica: recibe formularios con FastAPI, clasifícalos con IA y guarda el resultado en una hoja. También en Make y Zapier.
👁 113 lecturas
Un webhook es una direccion URL a la que una aplicacion envia datos automaticamente a otra en el momento exacto en que ocurre un evento: alguien rellena un formulario, llega un correo o se confirma un pago. En lugar de preguntar cada minuto si hay algo nuevo, simplemente esperas a que llamen a tu puerta. A continuación te muestro cómo funciona un webhook en la práctica: un servidor local en Python (FastAPI) recibe la solicitud de un formulario, un modelo de IA la clasifica y redacta un borrador de respuesta, y el resultado termina en una hoja de cálculo. Después explico cómo montar lo mismo en Make y Zapier. Este artículo forma parte de la serie Agentes de IA desde cero, en su etapa de automatizacion.
Estado a 4 de octubre de 2026
- Prueba: Windows 11, Python 3.13, FastAPI 0.142.2, uvicorn 0.54.0, modelo
openai/gpt-5.6-lunaa traves de OpenRouter. - Una solicitud: 1,7-2,1 s desde el envio hasta la respuesta; coste de unos 0,00014 EUR (0,00016 USD). Conversion orientativa calculada segun el tipo de cambio de referencia del BCE del 12/10/2026 (1 EUR = 1,1181 USD): https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml.
- Make: el plan gratuito incluye 1000 creditos al mes y 2 escenarios activos. Zapier: 100 tareas mensuales, solo Zaps de dos pasos, y los webhooks requieren planes de pago (desde 17,88 EUR o 19,99 USD al mes con facturacion anual; conversion basada en la tasa oficial del BCE mencionada).
- Código: paquete de inicio de agentes, archivos
06_webhook.pyy06_test_webhook.py.
Webhook, en palabras sencillas
Existen dos formas de que un programa se entere de una novedad:
- consultas periodicas (polling): tu programa revisa cada 5 minutos la bandeja de entrada o una hoja de calculo para comprobar si hay algo nuevo. Es un metodo sencillo, pero genera retrasos y desperdicia llamadas;
- webhook: le facilitas a otra aplicacion tu direccion (por ejemplo,
https://tudominio.es/webhook/formulario) y esta envia alli una peticion HTTP POST con datos en formato JSON de inmediato, en cuanto ocurre la accion.
Un webhook no es mas que una peticion ordinaria a una API, solo que en direccion inversa: en vez de llamar tu al servicio externo, el servicio te llama a ti. Si las peticiones HTTP y el formato JSON son conceptos nuevos para ti, puedes empezar por la guia de API.
Fuentes habituales de webhooks:
- formularios (Tally, Typeform, Google Forms mediante scripts, formularios de WordPress);
- pasarelas de pago (Stripe y otros sistemas notifican cobros completados);
- tiendas online (WooCommerce, Shopify: creacion de nuevos pedidos);
- herramientas de trabajo (GitHub, Slack, Trello, Calendly);
- plataformas de automatizacion (Make, Zapier y n8n cuentan con modulos preparados para recibir webhooks).
Que he construido
- Un formulario de contacto envia un JSON con tres campos: nombre, correo electronico y mensaje.
- Mi servidor valida un secreto en la cabecera (para evitar que terceros envien peticiones no deseadas).
- El modelo de IA recibe el mensaje y responde con un JSON: categoria, nivel de urgencia del 1 al 3, resumen y borrador de respuesta.
- El servidor anade una fila a un archivo CSV (el equivalente local a una hoja de calculo) y devuelve la respuesta procesada.
Código del servidor para el webhook
Instalacion: pip install fastapi uvicorn openai python-dotenv. En el archivo .env define las variables OPENROUTER_API_KEY y WEBHOOK_SECRET (una cadena larga y aleatoria).
"""06 - Webhook: el formulario envia la solicitud -> el servidor consulta al modelo -> el resultado se guarda en CSV y se devuelve.
Iniciar: uvicorn 06_webhook:app --port 8000 (o bien: python 06_webhook.py)
Probar: curl -X POST http://127.0.0.1:8000/webhook/formulario -H "X-Webhook-Secret: ..." -H "Content-Type: application/json" -d "{\"nombre\":\"Laura\",\"email\":\"laura@example.com\",\"mensaje\":\"La factura tiene el NIF mal\"}"
"""
import csv, datetime, json, os, pathlib
from dotenv import load_dotenv
from fastapi import FastAPI, Header, HTTPException
from openai import OpenAI
from pydantic import BaseModel
load_dotenv()
SECRETO = os.getenv("WEBHOOK_SECRET", "cambia-esto") # esta misma cadena la introduces en Make/Zapier/formulario
MODELO = os.getenv("MODEL", "openai/gpt-5.6-luna")
HOJA = pathlib.Path("solicitudes.csv")
client = OpenAI(base_url="https://openrouter.ai/api/v1", api_key=os.environ["OPENROUTER_API_KEY"])
app = FastAPI()
class Solicitud(BaseModel): # estructura esperada del JSON del formulario
nombre: str
email: str
mensaje: str
@app.post("/webhook/formulario")
def recibir(s: Solicitud, x_webhook_secret: str = Header(default="")):
if x_webhook_secret != SECRETO: # evita que cualquiera consuma tus tokens si conoce la URL
raise HTTPException(status_code=401, detail="secreto incorrecto")
r = client.chat.completions.create(model=MODELO, response_format={"type": "json_object"}, messages=[
{"role": "system", "content": "Eres asistente de atencion al cliente. Devuelve JSON con los campos: categoria (facturacion|reclamacion|"
"presupuesto|otros), urgencia (1-3, donde 3 es urgente), resumen (max 12 palabras), borrador_respuesta (2-3 frases, en espanol, de tu)."},
{"role": "user", "content": f"De: {s.nombre}\nMensaje: {s.mensaje}"}])
resultado = json.loads(r.choices[0].message.content)
nuevo = not HOJA.exists()
with HOJA.open("a", newline="", encoding="utf-8-sig") as f: # utf-8-sig permite a Excel abrir caracteres especiales sin fallos
w = csv.writer(f, delimiter=";")
if nuevo: w.writerow(["fecha_hora", "nombre", "email", "categoria", "urgencia", "resumen", "borrador_respuesta"])
w.writerow([datetime.datetime.now().isoformat(timespec="seconds"), s.nombre, s.email, resultado.get("categoria"),
resultado.get("urgencia"), resultado.get("resumen"), resultado.get("borrador_respuesta")])
return {"ok": True, **resultado, "coste_usd": getattr(r.usage, "cost", None)}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
Puntos clave:
class Solicitud(BaseModel)describe la forma que debe tener el JSON. FastAPI descarta automaticamente cualquier solicitud que carezca de los campos obligatorios (error 422), antes de gastar saldo en el modelo;- clave secreta en la cabecera
X-Webhook-Secret. Cualquier intento hacia la direccion sin esta clave recibe un error 401 y no genera ningun gasto; response_format={"type": "json_object"}fuerza al modelo a devolver exclusivamente un JSON estructurado, facil de volcar en columnas;utf-8-sigal guardar el CSV garantiza que herramientas como Excel interpreten correctamente las tildes y caracteres especiales.
Puesta en marcha y prueba practica
En una ventana del terminal inicio el servidor con: uvicorn 06_webhook:app --port 8000. En una segunda consola ejecuto un script que simula el formulario, enviando tres solicitudes reales mas un intento con secreto erroneo. Nota: en la prueba original los mensajes de entrada se probaron en polaco (aqui se muestran traducidos):
"""Envia 3 solicitudes de ejemplo al webhook local (igual que haria un formulario o Make/Zapier)."""
import os, time, requests
URL = "http://127.0.0.1:8000/webhook/formulario"
SECRETO = os.getenv("WEBHOOK_SECRET", "cambia-esto")
print("secreto incorrecto ->", requests.post(URL, json={"nombre": "X", "email": "x@example.com", "mensaje": "prueba"},
headers={"X-Webhook-Secret": "intento_aleatorio"}).status_code)
# Mensajes traducidos del material de prueba original ejecutado en polaco:
casos = [
("Ola", "Buenos dias, en la factura FV/2026/09/027 el NIF de mi empresa es incorrecto. Necesito la rectificacion antes del viernes porque cierro mes."),
("Marek", "Cuanto cuesta implementar un chatbot en una tienda online con 300 productos? Me interesaria para noviembre."),
("Kasia", "El cable que pedi ha llegado defectuoso, la clavija esta rota. Solicito el reembolso.")
]
for nombre, mensaje in casos:
t = time.time()
r = requests.post(URL, json={"nombre": nombre, "email": f"{nombre.lower()}@example.com", "mensaje": mensaje},
headers={"X-Webhook-Secret": SECRETO}, timeout=60)
print(f"\n{nombre}: {mensaje}\n-> HTTP {r.status_code} en {time.time() - t:.1f} s: {r.json()}")
Resultado de la medicion obtenida el 4 de octubre a las 14:11 (el test se ejecuto originalmente con textos en polaco; mostramos la traduccion de las respuestas recibidas):
> python 06_test_webhook.py
secreto incorrecto -> 401
Ola: Buenos dias, en la factura FV/2026/09/027 el NIF de mi empresa es incorrecto. Necesito la rectificacion antes del viernes porque cierro mes.
-> HTTP 200 en 2.1 s: {'ok': True, 'categoria': 'facturacion', 'urgencia': 3, 'resumen': 'NIF erroneo en factura, rectificacion necesaria para el viernes', 'szkic_odpowiedzi': 'Gracias por tu aviso: revisaremos la factura FV/2026/09/027 y prepararemos la rectificacion con el NIF correcto. Lo gestionaremos de forma prioritaria para que este lista antes del viernes.', 'coste_usd': 0.0001746}
Marek: Cuanto cuesta implementar un chatbot en una tienda online con 300 productos? Me interesaria para noviembre.
-> HTTP 200 en 1.8 s: {'ok': True, 'categoria': 'presupuesto', 'urgencia': 2, 'resumen': 'Consulta de presupuesto y plazo para chatbot en tienda', 'szkic_odpowiedzi': 'Hola Marek, prepararemos un presupuesto para la implementacion del chatbot en tu tienda con 300 productos y revisaremos la disponibilidad para noviembre. Por favor, facilitanos el enlace de la tienda y cuentanos que funciones deberia cubrir el bot.', 'coste_usd': 0.000162}
Kasia: El cable que pedi ha llegado defectuoso, la clavija esta rota. Solicito el reembolso.
-> HTTP 200 en 1.7 s: {'ok': True, 'categoria': 'reclamacion', 'urgencia': 2, 'resumen': 'Cable danado, clavija rota; la clienta solicita el reembolso.', 'szkic_odpowiedzi': 'Lamentamos que el cable haya llegado con desperfectos. Por favor, envianos fotos del dano y el numero de pedido para tramitar el reembolso.', 'coste_usd': 0.0001504}
> type solicitudes.csv
fecha_hora;nombre;email;categoria;urgencia;resumen;borrador_respuesta
2026-10-04T14:11:16;Ola;ola@example.com;facturacion;3;NIF erroneo en factura, rectificacion necesaria para el viernes;Gracias por tu aviso: revisaremos la factura FV/2026/09/027 y prepararemos la rectificacion con el NIF correcto. Lo gestionaremos de forma prioritaria para que este lista antes del viernes.
2026-10-04T14:11:18;Marek;marek@example.com;presupuesto;2;Consulta de presupuesto y plazo para chatbot en tienda;Hola Marek, prepararemos un presupuesto para la implementacion del chatbot en tu tienda con 300 productos y revisaremos la disponibilidad para noviembre. Por favor, facilitanos el enlace de la tienda y cuentanos que funciones deberia cubrir el bot.
2026-10-04T14:11:19;Kasia;kasia@example.com;reclamacion;2;"Cable danado, clavija rota; la clienta solicita el reembolso.";Lamentamos que el cable haya llegado con desperfectos. Por favor, envianos fotos del dano y el numero de pedido para tramitar el reembolso.
Conclusiones del test:
- la petición con un secreto inválido se rechazó de inmediato con código 401, sin invocar al modelo;
- las categorias asignadas fueron precisas en los tres ejemplos. El nivel de urgencia 3 solo se otorgo a la peticion con un plazo marcado («antes del viernes»);
- los borradores generados fueron coherentes y en el caso de la reclamación la IA solicitó fotos y el número de pedido por iniciativa propia;
- el coste por procesamiento oscilo en torno a 0,00015-0,00017 USD por solicitud (aproximadamente 0,00013-0,00015 EUR segun el tipo de cambio del BCE mencionado).
Un detalle tecnico a tener en cuenta: al usar curl en Git Bash bajo Windows pasando caracteres con tilde directamente en -d '...', la codificacion rota causo errores 400 en el servidor («There was an error parsing the body»). Se soluciona guardando el JSON en un archivo y enviandolo con --data-binary @archivo.json o utilizando el script en Python.
Como exponer un webhook a internet
Un servidor escuchando en 127.0.0.1 solo es accesible desde tu propia maquina. Para que un formulario publico pueda enviar datos, necesitas una URL accesible desde la red:
- para desarrollo y pruebas: una herramienta de tunelado como ngrok o Cloudflare Tunnel, que asigna una URL HTTPS temporal redirigida a tu puerto local 8000;
- en produccion continuada: un servidor privado virtual o una plataforma de despliegue como Railway, donde subes el código y dispones de una URL permanente;
- sin gestionar servidores: recibir el webhook directamente en plataformas como Make, Zapier o n8n para delegar la infraestructura.
Asegurate siempre de utilizar HTTPS y validar una clave secreta. Servicios consolidados como Stripe o GitHub firman cada paquete con HMAC; en ese caso se calcula la firma del cuerpo recibido y se valida contra la cabecera correspondiente.
La misma automatizacion en Make (sin programar)
- Crea un escenario nuevo y anade como primer elemento el modulo Webhooks, Custom webhook. La plataforma generara una URL propia.
- Pega esa URL en la configuracion de tu formulario (Tally, Typeform o WordPress) y haz un envio de prueba para que detecte la estructura JSON.
- Inserta un modulo de IA: OpenAI (o una llamada HTTP hacia OpenRouter) configurando las instrucciones del sistema y solicitando salida en JSON.
- Incorpora el modulo JSON, Parse JSON para extraer cada variable individualmente.
- Anade Google Sheets, Add a row y vincula cada variable con su columna de destino.
- Opcional: configura un filtro condicional si la urgencia es 3 para disparar un aviso prioritario.
En Make cada ejecucion consume un credito por modulo. El plan gratuito proporciona 1000 creditos al mes y 2 escenarios en ejecucion continua. Para mas detalles sobre su funcionamiento, consulta la guia Make: como funciona y que costes tiene.
La misma automatizacion en Zapier
- Disparador (Trigger): Webhooks by Zapier, Catch Hook para obtener la direccion de recepcion, o bien el disparador nativo de la aplicacion de formularios elegida.
- Accion: ChatGPT o AI by Zapier con la instruccion de clasificacion y formateo.
- Accion: Google Sheets, Create Spreadsheet Row.
La función Webhooks en Zapier está clasificada como función premium, requiriendo un plan de pago (Professional a partir de unos 17,88 EUR o 19,99 USD mensuales en facturación anual, o 26,82 EUR / 29,99 USD al mes en pago mensual; cálculo estimado según la tasa del BCE). Además, este flujo consta de tres pasos, superando el límite de dos del plan básico. Tienes una comparativa detallada en el artículo sobre Zapier: caracteristicas y precios.
FastAPI, Make o Zapier: qué opción elegir
| Opción | Coste fijo | Requisitos tecnicos | Perfil recomendado |
|---|---|---|---|
| Servidor propio (FastAPI) | Alojamiento (desde 0 EUR en local con tunel) | Fundamentos de Python | Control total del flujo sin pagar por cada paso ejecutado |
| n8n (autoalojado) | Edicion Community sin coste de licencia; coste del VPS | Despliegue y mantenimiento de servidor | Volumen alto de operaciones y soberania de datos |
| Make | Desde 0 EUR (plan gratis con 1000 creditos) | Solo navegador web | Flujos intermedios con bifurcaciones visuales |
| Zapier | Webhooks disponibles desde el plan Professional (desde aprox. 17,88 EUR / 19,99 USD al mes) | Solo navegador web | Mayor catalogo de integraciones directas y configuracion rapida |
Preguntas frecuentes
Que es un webhook en terminos sencillos?
Es una dirección web a la que un servicio externo envía información de manera automática en el mismo instante en que se produce un acontecimiento concreto, acompañada de los datos relevantes de dicho suceso.
En que se diferencia un webhook de una API tradicional?
Una API habitual funciona como una ventanilla a la que acudes a consultar cuando necesitas información. Un webhook funciona como un timbre: suena en tu sistema cuando el otro servicio tiene algo nuevo que entregarte. A nivel técnico, un webhook no es más que una llamada entrante hacia tu propia API.
Es seguro utilizar webhooks?
Depende de las capas de seguridad que configures. Los requisitos minimos son conexion cifrada HTTPS y validacion de un secreto en la cabecera. Para entornos de produccion criticos se recomienda anadir firmas criptograficas HMAC, control de marcas de tiempo contra ataques de repeticion y restricciones en el tamano de la carga util.
Como puedo probar un webhook sin tener un servidor expuesto?
Puedes ejecutar pruebas locales enviando peticiones desde scripts apuntando a 127.0.0.1 (como en el ejemplo de este artículo) o recurrir a herramientas de tunelado que abren un acceso temporal hacia tu máquina.
Que ocurre si mi servidor se encuentra apagado?
El comportamiento dependera del emisor. Pasarelas como Stripe reintentan la entrega de forma escalonada durante varias horas o dias. Otros formularios sencillos pueden perder el registro si la peticion falla. Por este motivo, los puntos de recepcion de webhooks deben procesar y confirmar la recepcion de inmediato, derivando las tareas lentas (como las consultas al modelo) a procesos en segundo plano.
Se puede enlazar un webhook directamente con un agente de IA?
Si, es el patron estandar para poner en marcha agentes basados en eventos: la llamada del webhook activa el ciclo de ejecucion del agente para consultar herramientas de forma autonoma. Encontraras el paso a paso en Como crear un agente de IA en Python.
Google · Tus fuentesBrilla más alto en tu Google - con un solo clicAñadir a fuentes preferidas →Fuentes y fecha de verificacion
- Tarifas y planes oficiales: Make, Zapier y n8n (consultados el 4 de octubre de 2026).
- Documentacion oficial de FastAPI.
- Pruebas de ejecucion: entorno local, 4 de octubre de 2026, 14:11. Los datos de las solicitudes de prueba son ficticios.


