TIL: How to trigger GH workflows via webhook

TIL: How to trigger GH workflows via webhook

This a quick post about GH workflows and how to trigger them from an external source

Zacbe Gonzalez · 2 minute read


So, I recently set up some Github actions to automatically deploy my personal website (a Gatsby static site) to GH Pages. I didn't have to do much - just used the available Gatsby template and added some environment variables so it could talk to Contentful.

TLDR: Skip to the solution and copy the cURL!

Initially, I wanted to avoid publishing the built version of my site by using the commands locally. But then I realized - how am I going to trigger this build action when new content is available on Contentful?

I knew about Contentful Webhooks because I'd used them with Netlify before and it was super easy. However, when I searched for an example of how to do it for GH, I couldn't find much. So, I kept digging until I found this cool post by Ondrej Polesny that put me on the right track.

The post is not very old, but it seems GH moves very fast! What worked for Ondrej didn't work for me.

Here are the key discoveries:

GH has an available API to a workflow dispatch event called GH dispatch event, which allows you to post an event to GH and trigger a workflow. Bingo! That was my solution. Except for one thing - I didn't read the documentation carefully enough and missed this important point: The User-Agent is required.

I started getting 403 errors from GH and this response:

Response: Request forbidden by administrative rules. Please make sure your request has a User-Agent header: (https://docs.github.com/en/rest/overview/resources-in-the-rest-api#user-agent-required). Check https://developer.github.com for other possible causes.

The solution

In the end, everything worked out and the solution was really simple! All you need is:

  • A GH personal access token

  • This URL:


  • This request body: {ref": "branch_name"}

  • The User-Agent header which can be your GH username or repo name

cURL Example:


curl --location --max-time 30 'https://api.github.com/repos/{{OWNER}}/{{REPO}}/actions/workflows/{{WORKFLOW_ID}}/dispatches' \--header 'Accept: application/vnd.github+json' \--header 'X-GitHub-Api-Version: 2022-11-28' \--header 'User-Agent: ${repo_name}' \--header 'Authorization: Bearer ${personal_token}' \--header 'Content-Type: application/json' \--data '{ "ref": "${branch_name}"}'


Note: The name can be the file name of your workflow, e.g. gatsby.yml.

That's it! Now I just needed to set up the webhook on Contentful and define my event filter. I don't want every action I do to trigger a new build/deploy of my website.

Helpful links: