# Webhooks

Los webhooks son la base de las funciones relacionadas con MLOps. Permiten escuchar nuevos cambios en repositorios específicos o en todos los repositorios de usuarios u organizaciones particulares que desees seguir. Esta guía explica primero cómo gestionar webhooks de forma programática. A continuación, veremos cómo aprovechar `huggingface_hub` para crear un servidor que escuche webhooks y desplegarlo en un Space.

Esta guía asume que estás familiarizado con el concepto de webhooks en Huggingface Hub. Para obtener más información sobre los webhooks en sí, debes leer primero esta [guía](https://huggingface.co/docs/hub/webhooks).

## Gestión de Webhooks

`huggingface_hub` te permite gestionar tus webhooks de forma programática. Puedes listar tus webhooks existentes, crear nuevos y actualizarlos, habilitarlos, deshabilitarlos o eliminarlos. Esta sección te guía a través de los procedimientos utilizando las funciones de la API de Hugging Face Hub.

### Creación de un Webhook

Para crear un nuevo webhook, use [create_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.create_webhook) y especifique la URL a la que deben enviarse los payloads, qué eventos deben vigilarse y, opcionalmente, establezca un dominio y un secreto para la seguridad.

```python
from huggingface_hub import create_webhook

# Example: Creating a webhook
webhook = create_webhook(
    url="https://webhook.site/your-custom-url",
    watched=[{"type": "user", "name": "your-username"}, {"type": "org", "name": "your-org-name"}],
    domains=["repo", "discussion"],
    secret="your-secret"
)
```

Un webhook también puede activar la ejecución de un Job en la infraestructura de Hugging face en lugar de enviar el payload a una URL. En este caso, es necesario pasar el ID de un Job de origen.

```python
from huggingface_hub import create_webhook

# Example: Creating a webhook that triggers a Job
webhook = create_webhook(
    job_id=job_id,
    watched=[{"type": "user", "name": "your-username"}, {"type": "org", "name": "your-org-name"}],
    domains=["repo", "discussion"],
    secret="your-secret"
)
```

El webhook activa el Job con la carga del webhook en la variable de entorno `WEBHOOK_PAYLOAD`. Los secretos del Job de origen no se copian al webhook. Si el Job activado necesita secretos (p. ej. `HF_TOKEN`), pásalos con `secrets={"HF_TOKEN": "hf_***"}`. Con [update_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.update_webhook), debes pasar `job_id` junto con `secrets`. Los secretos enumerados reemplazan los valores almacenados, una cadena vacía elimina un secreto y todos los demás secretos se conservan. Para obtener más información sobre Hugging Face Jobs, el hardware disponible (CPU, GPU) y los scripts de UV, consulta la [documentación de Jobs](./jobs).

### Listar Webhooks

Para ver todos los webhooks que has configurado, puedes listarlos con [list_webhooks()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.list_webhooks). Esto es útil para revisar sus IDs, URLs y estados.

```python
from huggingface_hub import list_webhooks

# Example: Listing all webhooks
webhooks = list_webhooks()
for webhook in webhooks:
    print(webhook)
```

### Actualización de un Webhook

Si necesitas cambiar la configuración de un webhook existente, como la URL o los eventos que observa, puedes actualizarlo usando [update_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.update_webhook).

```python
from huggingface_hub import update_webhook

# Example: Updating a webhook
updated_webhook = update_webhook(
    webhook_id="your-webhook-id",
    url="https://new.webhook.site/url",
    watched=[{"type": "user", "name": "new-username"}],
    domains=["repo"]
)
```

### Activar y desactivar Webhooks

Es posible que desee deshabilitar temporalmente un webhook sin eliminarlo. Esto se puede hacer usando [disable_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.disable_webhook), y el webhook se puede reactivar más adelante con [enable_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.enable_webhook).

```python
from huggingface_hub import enable_webhook, disable_webhook

# Example: Enabling a webhook
enabled_webhook = enable_webhook("your-webhook-id")
print("Enabled:", enabled_webhook)

# Example: Disabling a webhook
disabled_webhook = disable_webhook("your-webhook-id")
print("Disabled:", disabled_webhook)
```

### Eliminar un Webhook

Cuando un webhook ya no es necesario, se puede eliminar de forma permanente usando [delete_webhook()](/docs/huggingface_hub/v2.4.0/es/package_reference/hf_api#huggingface_hub.HfApi.delete_webhook).

```python
from huggingface_hub import delete_webhook

# Example: Deleting a webhook
delete_webhook("your-webhook-id")
```

### Gestión de Webhooks desde la CLI

Todas las operaciones anteriores también están disponibles desde la interfaz de línea de comandos `hf`. Esto resulta especialmente útil para la creación de scripts y flujos de trabajo agénticos.

```bash
# List all webhooks
>>> hf webhooks ls

# Get details about a specific webhook
>>> hf webhooks info <webhook_id>

# Create a webhook that pings a URL
>>> hf webhooks create --url https://example.com/hook --watch model:bert-base-uncased --domain repo

# Create a webhook that triggers a Job
>>> hf webhooks create --job-id <job_id> --watch user:julien-c

# Create a webhook that triggers a Job with your HF token as a secret
>>> hf webhooks create --job-id <job_id> --watch bucket:my-org/my-bucket --secrets HF_TOKEN

# Update an existing webhook
>>> hf webhooks update <webhook_id> --url https://new-url.com/hook

# Enable / disable a webhook
>>> hf webhooks enable <webhook_id>
>>> hf webhooks disable <webhook_id>

# Delete a webhook (with confirmation prompt)
>>> hf webhooks delete <webhook_id>
```

La opción `--watch` utiliza el formato `type:name`, donde type es uno de `model`, `dataset`, `space`, `org` o `user`. Puede repetirse para supervisar varios elementos. Para obtener la lista completa de opciones, ejecute `hf webhooks <command> --help`. Para más detalles, consulte la [guía de la CLI](./cli#hf-webhooks).

## Servidor de Webhooks

La clase base que utilizaremos en esta sección de guías es [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer). Es una clase para configurar fácilmente un servidor que puede recibir webhooks desde Huggingface Hub. El servidor se basa en una aplicación de [Gradio](https://gradio.app/). Incluye una interfaz de usuario para mostrar instrucciones para ti o para tus usuarios, y una API para escuchar los webhooks.

> [!TIP]
> Para ver un ejemplo en funcionamiento de un servidor de webhook, consulta el de [Spaces CI Bot](https://huggingface.co/spaces/spaces-ci-bot/webhook). Es un Space que lanza entornos efímeros cuando se abre un PR en un Space.

> [!WARNING]
> Esta es una [función experimental](../package_reference/environment_variables#hfhubdisableexperimentalwarning). Esto significa que seguimos trabajando en la mejora de la API. Es posible que se introduzcan cambios que rompan la compatibilidad en el futuro sin previo aviso. Asegúrate de fijar la versión de `huggingface_hub` en tus requisitos.

### Crear un punto de acceso

Implementar un punto de entrada de webhook es tan sencillo como decorar una función. Veamos un primer ejemplo para explicar los conceptos principales:

```python
# app.py
from huggingface_hub import webhook_endpoint, WebhookPayload

@webhook_endpoint
async def trigger_training(payload: WebhookPayload) -> None:
    if payload.repo.type == "dataset" and payload.event.action == "update":
        # Trigger a training job if a dataset is updated
        ...
```

Guarda este fragmento en un archivo llamado `'app.py'` y ejecútalo con `'python app.py'`. Deberías ver un mensaje como este:

```text
Webhook secret is not defined. This means your webhook endpoints will be open to everyone.
To add a secret, set `WEBHOOK_SECRET` as environment variable or pass it at initialization:
        `app = WebhooksServer(webhook_secret='my_secret', ...)`
For more details about webhook secrets, please refer to https://huggingface.co/docs/hub/webhooks#webhook-secret.
Running on local URL:  http://127.0.0.1:7860
Running on public URL: https://1fadb0f52d8bf825fc.gradio.live

This share link expires in 72 hours. For free permanent hosting and GPU upgrades (NEW!), check out Spaces: https://huggingface.co/spaces

Webhooks are correctly setup and ready to use:
  - POST https://1fadb0f52d8bf825fc.gradio.live/webhooks/trigger_training
Go to https://huggingface.co/settings/webhooks to setup your webhooks.
```

¡Buen trabajo! Acabas de lanzar un servidor de webhooks. Desglosemos exactamente lo que ocurrió:

1. Al decorar una función con [webhook_endpoint()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.webhook_endpoint), se ha creado un objeto [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer) en segundo plano.
Como puede ver, este servidor es una aplicación de Gradio que se ejecuta en http://127.0.0.1:7860. Si abre esta URL en su navegador, verá una página de inicio con instrucciones sobre los webhooks registrados.
2. Una aplicación de Gradio es, en el fondo, un servidor de FastAPI. Se ha añadido una nueva ruta POST `/webhooks/trigger_training` a este servidor.
Esta es la ruta que escuchará los webhooks y ejecutará la función `trigger_training` cuando se active. FastAPI analizará automáticamente el payload y lo pasará a la función como un objeto [WebhookPayload](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhookPayload). Este es un objeto `pydantic` que contiene toda la información sobre el evento que activó el webhook.
3. La aplicación de Gradio también abrió un túnel para recibir solicitudes desde internet. Esta es la parte interesante: puedes
configura un Webhook en https://huggingface.co/settings/webhooks apuntando a tu máquina local. Esto es útil para depurar tu servidor de webhooks e iterar rápidamente antes de desplegarlo en un Space.
4. Por último, los registros también te indican que tu servidor actualmente no está protegido por un secreto. Esto no es problemático para
depuración local, pero es algo que hay que tener en cuenta para más adelante.

> [!WARNING]
> Por defecto, el servidor se inicia al final de su script. Si lo está ejecutando en un notebook, puede iniciar el servidor manualmente llamando a `decorated_function.launch()`. Dado que se utiliza un servidor único, solo tiene que iniciar el servidor una vez, incluso si tiene múltiples puntos de acceso.

### Configurar un Webhook

Ahora que tienes un servidor de webhook en ejecución, quieres configurar un Webhook para empezar a recibir mensajes. Ve a https://huggingface.co/settings/webhooks, haz clic en "Add a new webhook" y configura tu Webhook. Establece los repositorios objetivo que quieres vigilar y la URL del Webhook, aquí `https://1fadb0f52d8bf825fc.gradio.live/webhooks/trigger_training`.

¡Y eso es todo! Ahora puedes activar ese webhook actualizando el repositorio de destino (por ejemplo, enviando un commit). Consulta la pestaña Activity de tu Webhook para ver los eventos que se han activado. Ahora que tienes una configuración funcional, puedes probarla e iterar rápidamente. Si modificas tu código y reinicias el servidor, es posible que tu URL pública cambie. Asegúrate de actualizar la configuración del webhook en el Hub si es necesario.

### Desplegar en un Space

Ahora que tienes un servidor de webhook funcional, el objetivo es desplegarlo en un Space. Ve a https://huggingface.co/new-space para crear un Space. Asígname un nombre, selecciona el SDK de Gradio y haz clic en "Create Space". Sube tu código al Space en un archivo llamado `app.py`. Tu Space se iniciará automáticamente. Para más detalles sobre Spaces, consulta esta [guía](https://huggingface.co/docs/hub/spaces-overview).

Tu servidor de webhook ahora se está ejecutando en un Space público. En la mayoría de los casos, querrás protegerlo con un secreto. Ve a la configuración de tu Space > Sección "Repository secrets" > "Add a secret". Establece la variable de entorno `WEBHOOK_SECRET` con el valor que prefieras. Vuelve a la [configuración de Webhooks](https://huggingface.co/settings/webhooks) y establece el secreto en la configuración del webhook. Ahora, solo se aceptarán las solicitudes con el secreto correcto en tu servidor.

¡Y listo! Tu Space ya está preparado para recibir webhooks desde el Hub. Ten en cuenta que, si ejecutas el Space en un hardware gratuito 'cpu-basic', se cerrará tras 48 horas de inactividad. Si necesitas un Space permanente, deberías considerar configurarlo con un [hardware mejorado](https://huggingface.co/docs/hub/spaces-gpus#hardware-specs).

### Uso avanzado

La guía anterior explicó la forma más rápida de configurar un [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer). En esta sección, veremos cómo personalizarlo aún más.

#### Varios puntos finales

Puedes registrar varios puntos de conexión en el mismo servidor. Por ejemplo, es posible que quieras tener un punto de conexión para iniciar un trabajo de entrenamiento y otro para iniciar la evaluación de un modelo. Puedes hacer esto añadiendo varios decoradores `@webhook_endpoint`:

```python
# app.py
from huggingface_hub import webhook_endpoint, WebhookPayload

@webhook_endpoint
async def trigger_training(payload: WebhookPayload) -> None:
    if payload.repo.type == "dataset" and payload.event.action == "update":
        # Trigger a training job if a dataset is updated
        ...

@webhook_endpoint
async def trigger_evaluation(payload: WebhookPayload) -> None:
    if payload.repo.type == "model" and payload.event.action == "update":
        # Trigger an evaluation job if a model is updated
        ...
```

Lo que creará dos puntos finales:

```text
(...)
Webhooks are correctly setup and ready to use:
  - POST https://1fadb0f52d8bf825fc.gradio.live/webhooks/trigger_training
  - POST https://1fadb0f52d8bf825fc.gradio.live/webhooks/trigger_evaluation
```

#### Servidor personalizado

Para obtener más flexibilidad, también puedes crear directamente un objeto [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer). Esto es útil si quieres personalizar la página de inicio de tu servidor. Puedes hacerlo pasando una [Gradio UI](https://gradio.app/docs/#blocks) que sobrescribirá la predeterminada. Por ejemplo, puedes añadir instrucciones para tus usuarios o un formulario para activar manualmente los webhooks. Al crear un [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer), puedes registrar nuevos webhooks usando el decorador `add_webhook()`.

Aquí hay un ejemplo completo:

```python
import gradio as gr
from fastapi import Request
from huggingface_hub import WebhooksServer, WebhookPayload

# 1. Define  UI
with gr.Blocks() as ui:
    ...

# 2. Create WebhooksServer with custom UI and secret
app = WebhooksServer(ui=ui, webhook_secret="my_secret_key")

# 3. Register webhook with explicit name
@app.add_webhook("/say_hello")
async def hello(payload: WebhookPayload):
    return {"message": "hello"}

# 4. Register webhook with implicit name
@app.add_webhook
async def goodbye(payload: WebhookPayload):
    return {"message": "goodbye"}

# 5. Start server (optional)
app.launch()
```

1. Definimos una interfaz de usuario personalizada usando bloques de Gradio. Esta interfaz se mostrará en la página de inicio del servidor.
2. Creamos un objeto [WebhooksServer()](/docs/huggingface_hub/v2.4.0/es/package_reference/webhooks_server#huggingface_hub.WebhooksServer) con una interfaz de usuario personalizada y un secreto. El secreto es opcional y se puede establecer con
la variable de entorno `WEBHOOK_SECRET`.
3. Registramos un webhook con un nombre explícito. Esto creará un punto de acceso en `/webhooks/say_hello`.
4. Registramos un webhook con un nombre implícito. Esto creará un punto de acceso en `/webhooks/goodbye`.
5. Iniciamos el servidor. Esto es opcional, ya que el servidor se iniciará automáticamente al final del script.

