Start a workflow from a webhook
A workflow can start when another service sends it a request: GitHub when an issue opens, Stripe when a payment succeeds, a form when someone submits it, or Zapier and Make for the apps they connect. Your computer has no public address, so the request goes to Kitewell’s relay, which hands it to Kitewell on your computer. No port to open, no tunnel to set up.
Webhooks are part of Kitewell Personal and Team, and need Kitewell signed in to Dagu Cloud.
Turn on a webhook
Section titled “Turn on a webhook”- Open a saved workflow and choose Schedule, or the When this runs card.
- Under Webhook, choose Turn on. The URL appears after a moment:
https://hooks.kitewell.app/…. - Choose Copy and paste the URL into the service that sends requests.
- Choose Send test request to try the whole way: Kitewell sends a request to its own URL, and it comes back through the relay like any other. It starts a run, as a real request would, and opens under Recent requests to show what arrived.
The When this runs card then shows Webhook on. Only people who can edit the workflow see its URL. API keys and connected apps cannot read it.
Let the assistant use the request
Section titled “Let the assistant use the request”You don’t need to know how a request is laid out to use it:
- Have the real service send one request, such as by opening a test issue on GitHub.
- Under Recent requests, choose Details beside it to see what it carried.
- Choose Build steps from this request. The assistant opens on that request. Finish the sentence with what you need, such as “the issue title and who opened it, then post them to Slack”, and send it.
The assistant reads the request itself, proposes the steps, and saves nothing until you apply them.
Read the request in a step
Section titled “Read the request in a step”Each request starts one run, and run history shows its trigger as Webhook. Steps read the request from two environment variables:
WEBHOOK_PAYLOADholds the body as it was sent.WEBHOOK_HEADERSholds the headers as JSON: lowercase names, each with a list of values, such as{"x-github-event":["issues"]}.Authorizationand cookies are left out.
You don’t declare either one as an input. To pick one field out of a JSON
body, such as the issue’s title, ask the assistant with
Build steps from this request: it adds a step that picks the field out,
and later steps read it by name, such as ${steps.issue.outputs.title}. An
AI step can take the whole body in its prompt as text.
The body is whatever the sender sent, so treat it as untrusted. A command
reads it from its environment, as "$WEBHOOK_PAYLOAD" in a macOS shell or
$env:WEBHOOK_PAYLOAD in PowerShell on Windows. Never write
${env.WEBHOOK_PAYLOAD}, or a value taken from it, into the command text,
where its quotes would become code. The assistant
knows these variables: ask it to build the workflow from the request you
expect.
Set up the sender
Section titled “Set up the sender”GitHub
Section titled “GitHub”- In the repository, or the organization, open Settings → Webhooks and choose Add webhook.
- Paste the URL into Payload URL.
- Set Content type to
application/json. GitHub’s default sends the body as form data (payload=…), which is not JSON. - Under Which events would you like to trigger this webhook?, choose Let me select individual events and pick only the ones the workflow needs. Every event GitHub sends starts a run, unless Only these events leaves it out.
- To have Kitewell check GitHub’s signature, paste the secret Kitewell makes into Secret. See Check who sent the request.
GitHub’s Recent Deliveries tab shows each request with Kitewell’s answer,
202 when the relay took it.
Other services
Section titled “Other services”Any service that sends an HTTP POST works. In Stripe, add an event
destination with the URL and choose the events. In a Slack app, paste the URL
under Event Subscriptions. In Zapier or Make, add a webhook action that posts
to the URL. A form service usually has a webhook or “notify a URL” setting.
Check who sent the request
Section titled “Check who sent the request”Anyone who has the URL can send a request to it. To start runs only for requests the real sender signed, choose that sender under Accept requests from: GitHub, Stripe, Slack, or Standard Webhooks. Anyone with the URL turns the check off again.
- GitHub: choose Make a secret. Kitewell shows the secret once; paste it into the GitHub webhook’s Secret. New secret replaces it, and GitHub’s requests are rejected until you paste the new one there.
- Stripe: paste the event destination’s signing secret, which starts with
whsec_, into Signing secret, and choose Save. - Slack: paste the Signing Secret from your Slack app’s Basic Information into Signing secret, and choose Save. Kitewell’s relay answers Slack’s URL check even while this computer is away.
- Standard Webhooks: paste the signing secret the sender shows, which starts
with
whsec_, into Signing secret, and choose Save.
A request without a valid signature starts no run and shows Rejected, with the reason. A Stripe, Slack, or Standard Webhooks signature must be made within five minutes of when the relay received the request, so a request that waited at the relay still passes. Send test request is signed too.
Take only some events
Section titled “Take only some events”Only these events names the events whose requests start runs, separated
by commas, such as issues.opened, invoice.paid. A name also takes the events
under it: issues takes issues.opened and every other issues event.
Seen lately: offers the events of recent requests, one click each. Choose
Save; left empty, every event starts a run.
Kitewell names an event the way its sender does: GitHub’s event and action
joined with a dot, the type in the body for Stripe and Standard Webhooks
senders, and for Slack, the type of the event its callback carries.
A request about any other event, or one that names no event, starts no run and shows Skipped. So does GitHub’s ping, which only checks the URL.
When your computer is asleep or offline
Section titled “When your computer is asleep or offline”The relay answers the sender at once, whether or not your computer is reachable. Requests wait at the relay for up to 7 days, and run, oldest first, when Kitewell connects again. Up to 1,000 can wait for one computer; after that, senders are asked to try again later.
Recent requests
Section titled “Recent requests”The Webhook section lists the latest 20 requests: when each arrived, what it
was about as the sender names it (such as GitHub’s issues.opened or
Stripe’s payment_intent.succeeded), its size, and its result. The list
updates while it is open.
Details opens a request: its body, laid out so it is easy to read, and its headers, each with Copy, plus Build steps from this request and View run →. A request that started no run shows why instead, because its body is kept only with a run.
| Result | Meaning |
|---|---|
| Run started | The request started a run. A request the relay sent twice starts one run. |
| Failed | The run could not be queued, for example because the project’s engine is stopped. Kitewell retries a busy or recovering engine for 10 minutes first. |
| Ignored | The paid plan has ended, or the workflow is not in your plan. |
| Rejected | The request had no valid signature from the sender chosen under Accept requests from. |
| Skipped | The request is about an event the webhook does not take, or is GitHub’s ping. |
Keep the URL private
Section titled “Keep the URL private”Unless the webhook checks who sent the request, anyone who has the URL can start the workflow. Treat it like a password.
- New URL replaces it at once; the old URL answers
404. Paste the new one wherever the old one was. - Turn off stops the URL the same way. Turning the webhook on again makes a new URL.
A webhook URL belongs to one computer. Turning on the same workflow’s webhook on a teammate’s computer gives that computer its own URL. A restored backup starts with webhooks off.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Request body | 512 KiB of text |
| Requests per URL | 60 a minute |
| Requests waiting for a computer | 1,000, for up to 7 days |
The relay answers:
| Status | Meaning |
|---|---|
202 |
Accepted. The body is {"id": "…"}. |
404 |
Not a webhook URL, or it was turned off or replaced. |
413 |
The body is over 512 KiB. |
415 |
The body is not UTF-8 text. |
429 |
More than 60 requests this minute; retry after the Retry-After seconds. |
503 |
1,000 requests are already waiting for this computer. |
On Windows, a body larger than about 30,000 characters may fail to start a run, and the request shows Failed. GitHub push and pull request events can be that large. A fix is on the way.
If the paid plan ends, or the workflow is no longer in your plan, the URL still accepts requests, but they start nothing and show Ignored. Signing up again needs no new URL.
Where the request goes
Section titled “Where the request goes”The request passes through Kitewell’s relay at hooks.kitewell.app, on Cloudflare. The relay keeps it only until your computer takes it, for at most 7 days, and stores only a hash of the secret part of each URL. On your computer, the body is kept with its run, like any run input, for the retention you set. See What leaves your computer.
Troubleshooting
Section titled “Troubleshooting”- “Getting the URL from Kitewell’s relay…” doesn’t go away. Check that Kitewell is signed in to Dagu Cloud and the computer is online, then turn the webhook off and on.
- A new URL answers
404. Wait a few seconds for Kitewell to give the relay the new URL. - A step cannot parse the body from GitHub. Set Content type to
application/jsonin the GitHub webhook. - A request shows Failed. The row gives the reason. For a stopped project, start it from the menu bar menu or the tray menu, then send the request again.