
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI can see the issue! GitHub's repository dispatch API requires a specific payload structure, but Sanity webhooks by default send the entire document with all its Sanity-specific fields like _id, _type, _createdAt, etc. GitHub is rejecting this because it only expects event_type (required) and optionally client_payload.
Here's how to fix this:
When setting up your webhook in Sanity (either via the Studio or API), you need to use a projection to transform the payload into the format GitHub expects:
https://api.github.com/repos/{owner}/{repo}/dispatchesAuthorization: Bearer YOUR_GITHUB_PAT (Personal Access Token with repo scope)Accept: application/vnd.github.v3+json{
"event_type": "sanity-webhook",
"client_payload": {
"documentId": _id,
"documentType": _type,
"slug": slug.current,
"title": title
}
}The projection uses GROQ syntax to reshape your document data into the exact structure GitHub expects. The event_type field is required by GitHub, and client_payload can contain whatever custom data you want to pass to your GitHub Actions workflow.
You can then access this data in your workflow:
on:
repository_dispatch:
types: [sanity-webhook]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Use payload data
run: |
echo "Document ID: ${{ github.event.client_payload.documentId }}"
echo "Title: ${{ github.event.client_payload.title }}"If you need more control over the payload transformation or want to add conditional logic, consider using Sanity Functions instead of direct webhooks. Functions are the modern, recommended approach for reacting to content changes - they're serverless compute modules that run within Sanity with native integration, automatic scaling, and better security.
Functions can listen to document changes and make custom HTTP requests with complete control over the payload format:
// sanity.blueprint.ts
import {defineBlueprint} from 'sanity'
export default defineBlueprint({
functions: [
{
name: 'trigger-github-action',
runtime: 'nodejs22',
handler: './functions/triggerGithub',
events: {
documentChanges: {
filter: '_type == "post"'
}
}
}
]
})Then in your function handler, you have full control to format the GitHub API request exactly as needed, handle errors, add retry logic, etc.
The webhook projection approach should solve your immediate issue though - just make sure your GitHub PAT has the correct repo scope and the projection transforms your document into the event_type + client_payload structure GitHub expects!
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store