HuggingFace Webhook payload handling and signature verification.
Helps build webhook receivers that can verify payloads are genuinely from HuggingFace and parse structured webhook events.
See: https://huggingface.co/docs/hub/webhooks
Webhook payload structure
HuggingFace sends JSON POST requests with:
X-Webhook-Secretheader (if configured)- A JSON body with
event,repo,discussion,comment,updatedRefs, etc.
Example (with Plug/Phoenix)
defmodule MyAppWeb.WebhookController do
use MyAppWeb, :controller
def receive(conn, _params) do
secret = Application.get_env(:my_app, :hf_webhook_secret)
case HuggingfaceClient.Hub.WebhooksServer.verify_and_parse(conn.body_params,
secret: secret,
List.first(header_secret: get_req_header(conn, "x-webhook-secret"))
) do
{:ok, event} ->
handle_event(event)
send_resp(conn, 200, "ok")
{:error, reason} ->
send_resp(conn, 400, reason)
end
end
defp handle_event(%{"event" => %{"action" => "create", "scope" => "repo"}} = event) do
IO.puts("Repo created: #{event["repo"]["name"]}")
end
defp handle_event(%{"event" => %{"scope" => "discussion"}} = event) do
IO.puts("Discussion event: #{event["discussion"]["title"]}")
end
defp handle_event(_event), do: :ok
end
Summary
Functions
Returns true if the event is a comment on a discussion or PR.
Returns true if the event involves a discussion or pull request.
Parses a raw webhook payload into a structured event map.
Returns true if the event is a pull request (not a plain discussion).
Returns true if the event is a repository configuration change.
Returns true if the event is a repository content change (code push, file upload).
Returns the list of updated git branches from a repo content event.
Returns the list of updated tags from a repo content event.
Verifies a webhook payload's authenticity and parses it.
Verifies that the X-Webhook-Secret header matches the configured secret.
Functions
Returns true if the event is a comment on a discussion or PR.
Returns true if the event involves a discussion or pull request.
Parses a raw webhook payload into a structured event map.
Event fields
"event"— map with"action"and"scope":action:"create","update","delete","move"scope:"repo","discussion","comment","repo.config","repo.content"
"repo"— repository info (type, name, id, private, url)"discussion"— present for discussion/PR events"comment"— present for comment events"updatedRefs"— list of updated git refs (for repo.content events)"movedTo"— present for move events"webUrl"— direct URL to the event location
Example
event = HuggingfaceClient.Hub.WebhooksServer.parse_event(raw_payload)
case event["event"]["scope"] do
"repo" -> handle_repo_event(event)
"discussion" -> handle_discussion_event(event)
"comment" -> handle_comment_event(event)
_ -> :ok
end
Returns true if the event is a pull request (not a plain discussion).
Returns true if the event is a repository configuration change.
Returns true if the event is a repository content change (code push, file upload).
Returns the list of updated git branches from a repo content event.
Example
branches = HuggingfaceClient.Hub.WebhooksServer.updated_branches(event)
# ["main", "dev"]
Returns the list of updated tags from a repo content event.
Verifies a webhook payload's authenticity and parses it.
Options
:secret— your webhook's configured secret (required for verification):header_secret— value of theX-Webhook-Secretheader from the request:skip_verification— skip secret verification (not recommended for production)
Returns
{:ok, parsed_event}— map with structured webhook data{:error, reason}— string explaining what went wrong
Example
# In a Phoenix controller
case HuggingfaceClient.Hub.WebhooksServer.verify_and_parse(conn.body_params,
secret: "my-webhook-secret",
List.first(header_secret: get_req_header(conn, "x-webhook-secret"))
) do
{:ok, event} -> handle_event(event)
{:error, msg} -> Logger.warning("Invalid webhook: #{msg}")
end
Verifies that the X-Webhook-Secret header matches the configured secret.
Returns :ok or {:error, reason}.
Example
:ok = HuggingfaceClient.Hub.WebhooksServer.verify_secret(
"my-webhook-secret",
header_secret: "my-webhook-secret"
)