# Webhooks Server

Webhooks are a foundation for MLOps-related features. They allow you to listen for new changes on specific repos or to
all repos belonging to particular users/organizations you're interested in following. To learn
more about webhooks on the Huggingface Hub, you can read the Webhooks [guide](https://huggingface.co/docs/hub/webhooks).

> [!TIP]
> Check out this [guide](../guides/webhooks_server) for a step-by-step tutorial on how to setup your webhooks server and
> deploy it as a Space.

> [!WARNING]
> This is an experimental feature. This means that we are still working on improving the API. Breaking changes might be
> introduced in the future without prior notice. Make sure to pin the version of `huggingface_hub` in your requirements.
> A warning is triggered when you use an experimental feature. You can disable it by setting `HF_HUB_DISABLE_EXPERIMENTAL_WARNING=1` as an environment variable.

## Server

The server is a [Gradio](https://gradio.app/) app. It has a UI to display instructions for you or your users and an API
to listen to webhooks. Implementing a webhook endpoint is as simple as decorating a function. You can then debug it
by redirecting the Webhooks to your machine (using a Gradio tunnel) before deploying it to a Space.

### WebhooksServer[[huggingface_hub.WebhooksServer]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>huggingface_hub.WebhooksServer</name><anchor>huggingface_hub.WebhooksServer</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py#L43</source><parameters>[{"name": "*args", "val": ""}, {"name": "**kwargs", "val": ""}]</parameters><paramsdesc>- **ui** (`gradio.Blocks`, optional) --
  A Gradio UI instance to be used as the Space landing page. If `None`, a UI displaying instructions
  about the configured webhooks is created.
- **webhook_secret** (`str`, optional) --
  A secret key to verify incoming webhook requests. You can set this value to any secret you want as long as
  you also configure it in your [webhooks settings panel](https://huggingface.co/settings/webhooks). You
  can also set this value as the `WEBHOOK_SECRET` environment variable. If no secret is provided, the
  webhook endpoints are opened without any security.</paramsdesc><paramgroups>0</paramgroups></docstring>

The [WebhooksServer()](/docs/huggingface_hub/main/en/package_reference/webhooks_server#huggingface_hub.WebhooksServer) class lets you create an instance of a Gradio app that can receive Huggingface webhooks.
These webhooks can be registered using the `add_webhook()` decorator. Webhook endpoints are added to
the app as a POST endpoint to the FastAPI router. Once all the webhooks are registered, the `launch` method has to be
called to start the app.

It is recommended to accept [WebhookPayload](/docs/huggingface_hub/main/en/package_reference/webhooks_server#huggingface_hub.WebhookPayload) as the first argument of the webhook function. It is a Pydantic
model that contains all the information about the webhook event. The data will be parsed automatically for you.

Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to set up your
WebhooksServer and deploy it on a Space.

> [!WARNING]
> `WebhooksServer` is experimental. Its API is subject to change in the future.

> [!WARNING]
> You must have `gradio` installed to use `WebhooksServer` (`pip install --upgrade gradio`).



<ExampleCodeBlock anchor="huggingface_hub.WebhooksServer.example">

Example:

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

with gr.Blocks() as ui:
    ...

app = WebhooksServer(ui=ui, webhook_secret="my_secret_key")

@app.add_webhook("/say_hello")
async def hello(payload: WebhookPayload):
    return {"message": "hello"}

app.launch()
```

</ExampleCodeBlock>


</div>

### @webhook_endpoint[[huggingface_hub.webhook_endpoint]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>huggingface_hub.webhook_endpoint</name><anchor>huggingface_hub.webhook_endpoint</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_server.py#L226</source><parameters>[{"name": "path", "val": ": typing.Optional[str] = None"}]</parameters><paramsdesc>- **path** (`str`, optional) --
  The URL path to register the webhook function. If not provided, the function name will be used as the path.
  In any case, all webhooks are registered under `/webhooks`.</paramsdesc><paramgroups>0</paramgroups></docstring>
Decorator to start a [WebhooksServer()](/docs/huggingface_hub/main/en/package_reference/webhooks_server#huggingface_hub.WebhooksServer) and register the decorated function as a webhook endpoint.

This is a helper to get started quickly. If you need more flexibility (custom landing page or webhook secret),
you can use [WebhooksServer()](/docs/huggingface_hub/main/en/package_reference/webhooks_server#huggingface_hub.WebhooksServer) directly. You can register multiple webhook endpoints (to the same server) by using
this decorator multiple times.

Check out the [webhooks guide](../guides/webhooks_server) for a step-by-step tutorial on how to set up your
server and deploy it on a Space.

> [!WARNING]
> `webhook_endpoint` is experimental. Its API is subject to change in the future.

> [!WARNING]
> You must have `gradio` installed to use `webhook_endpoint` (`pip install --upgrade gradio`).



Examples:
The default usage is to register a function as a webhook endpoint. The function name will be used as the path.
The server will be started automatically at exit (i.e. at the end of the script).

<ExampleCodeBlock anchor="huggingface_hub.webhook_endpoint.example">

```python
from huggingface_hub import webhook_endpoint, WebhookPayload

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

# Server is automatically started at the end of the script.
```

</ExampleCodeBlock>

Advanced usage: register a function as a webhook endpoint and start the server manually. This is useful if you
are running it in a notebook.

<ExampleCodeBlock anchor="huggingface_hub.webhook_endpoint.example-2">

```python
from huggingface_hub import webhook_endpoint, WebhookPayload

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

# Start the server manually
trigger_training.launch()
```

</ExampleCodeBlock>


</div>

## Payload[[huggingface_hub.WebhookPayload]]

[WebhookPayload](/docs/huggingface_hub/main/en/package_reference/webhooks_server#huggingface_hub.WebhookPayload) is the main data structure that contains the payload from Webhooks. This is
a `pydantic` class which makes it very easy to use with FastAPI. If you pass it as a parameter to a webhook endpoint, it
will be automatically validated and parsed as a Python object.

For more information about webhooks payload, you can refer to the Webhooks Payload [guide](https://huggingface.co/docs/hub/webhooks#webhook-payloads).

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayload</name><anchor>huggingface_hub.WebhookPayload</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L130</source><parameters>[{"name": "event", "val": ": WebhookPayloadEvent"}, {"name": "repo", "val": ": WebhookPayloadRepo"}, {"name": "discussion", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadDiscussion] = None"}, {"name": "comment", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadComment] = None"}, {"name": "webhook", "val": ": WebhookPayloadWebhook"}, {"name": "movedTo", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadMovedTo] = None"}, {"name": "updatedRefs", "val": ": typing.Optional[list[huggingface_hub._webhooks_payload.WebhookPayloadUpdatedRef]] = None"}]</parameters></docstring>


</div>

### WebhookPayload[[huggingface_hub.WebhookPayload]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayload</name><anchor>huggingface_hub.WebhookPayload</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L130</source><parameters>[{"name": "event", "val": ": WebhookPayloadEvent"}, {"name": "repo", "val": ": WebhookPayloadRepo"}, {"name": "discussion", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadDiscussion] = None"}, {"name": "comment", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadComment] = None"}, {"name": "webhook", "val": ": WebhookPayloadWebhook"}, {"name": "movedTo", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadMovedTo] = None"}, {"name": "updatedRefs", "val": ": typing.Optional[list[huggingface_hub._webhooks_payload.WebhookPayloadUpdatedRef]] = None"}]</parameters></docstring>


</div>

### WebhookPayloadComment[[huggingface_hub.WebhookPayloadComment]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadComment</name><anchor>huggingface_hub.WebhookPayloadComment</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L95</source><parameters>[{"name": "id", "val": ": str"}, {"name": "author", "val": ": ObjectId"}, {"name": "hidden", "val": ": bool"}, {"name": "content", "val": ": typing.Optional[str] = None"}, {"name": "url", "val": ": WebhookPayloadUrl"}]</parameters></docstring>


</div>

### WebhookPayloadDiscussion[[huggingface_hub.WebhookPayloadDiscussion]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadDiscussion</name><anchor>huggingface_hub.WebhookPayloadDiscussion</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L102</source><parameters>[{"name": "id", "val": ": str"}, {"name": "num", "val": ": int"}, {"name": "author", "val": ": ObjectId"}, {"name": "url", "val": ": WebhookPayloadUrl"}, {"name": "title", "val": ": str"}, {"name": "isPullRequest", "val": ": bool"}, {"name": "status", "val": ": typing.Literal['closed', 'draft', 'open', 'merged']"}, {"name": "changes", "val": ": typing.Optional[huggingface_hub._webhooks_payload.WebhookPayloadDiscussionChanges] = None"}, {"name": "pinned", "val": ": typing.Optional[bool] = None"}]</parameters></docstring>


</div>

### WebhookPayloadDiscussionChanges[[huggingface_hub.WebhookPayloadDiscussionChanges]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadDiscussionChanges</name><anchor>huggingface_hub.WebhookPayloadDiscussionChanges</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L90</source><parameters>[{"name": "base", "val": ": str"}, {"name": "mergeCommitId", "val": ": typing.Optional[str] = None"}]</parameters></docstring>


</div>

### WebhookPayloadEvent[[huggingface_hub.WebhookPayloadEvent]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadEvent</name><anchor>huggingface_hub.WebhookPayloadEvent</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L85</source><parameters>[{"name": "action", "val": ": typing.Literal['create', 'delete', 'move', 'update']"}, {"name": "scope", "val": ": str"}]</parameters></docstring>


</div>

### WebhookPayloadMovedTo[[huggingface_hub.WebhookPayloadMovedTo]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadMovedTo</name><anchor>huggingface_hub.WebhookPayloadMovedTo</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L76</source><parameters>[{"name": "name", "val": ": str"}, {"name": "owner", "val": ": ObjectId"}]</parameters></docstring>


</div>

### WebhookPayloadRepo[[huggingface_hub.WebhookPayloadRepo]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadRepo</name><anchor>huggingface_hub.WebhookPayloadRepo</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L113</source><parameters>[{"name": "id", "val": ": str"}, {"name": "owner", "val": ": ObjectId"}, {"name": "head_sha", "val": ": typing.Optional[str] = None"}, {"name": "name", "val": ": str"}, {"name": "private", "val": ": bool"}, {"name": "subdomain", "val": ": typing.Optional[str] = None"}, {"name": "tags", "val": ": typing.Optional[list[str]] = None"}, {"name": "type", "val": ": typing.Literal['dataset', 'model', 'space']"}, {"name": "url", "val": ": WebhookPayloadUrl"}]</parameters></docstring>


</div>

### WebhookPayloadUrl[[huggingface_hub.WebhookPayloadUrl]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadUrl</name><anchor>huggingface_hub.WebhookPayloadUrl</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L71</source><parameters>[{"name": "web", "val": ": str"}, {"name": "api", "val": ": typing.Optional[str] = None"}]</parameters></docstring>


</div>

### WebhookPayloadWebhook[[huggingface_hub.WebhookPayloadWebhook]]

<div class="docstring border-l-2 border-t-2 pl-4 pt-3.5 border-gray-100 rounded-tl-xl mb-6 mt-8">


<docstring><name>class huggingface_hub.WebhookPayloadWebhook</name><anchor>huggingface_hub.WebhookPayloadWebhook</anchor><source>https://github.com/huggingface/huggingface_hub/blob/main/src/huggingface_hub/_webhooks_payload.py#L81</source><parameters>[{"name": "id", "val": ": str"}, {"name": "version", "val": ": typing.Literal[3]"}]</parameters></docstring>


</div>

<EditOnGithub source="https://github.com/huggingface/huggingface_hub/blob/main/docs/source/en/package_reference/webhooks_server.md" />