Skip to main content
An incoming webhook starts a Bolt schedule when another tool sends a POST request to its URL with its secret. Use one for any tool that can send an HTTP request, such as Jira Automation, Zapier, a CI job, or a script, without setting up an API key for the Bolt API. Tools that sign their webhooks, such as Linear, GitHub, and Stripe, can call it too: see Authenticate the sender. In the app, each incoming webhook is listed as a Trigger URL.

Before you start

  • To create and manage incoming webhooks, you need the Admin, Workspace Admin, or Developer role. Anyone who can open Bolt can see them and the requests they receive.
  • The schedule can be built in the Bolt UI, new or already deployed, or defined in YAML with trigger_on_webhook: true.

Create an incoming webhook

On an existing schedule

  1. Open the schedule in Bolt and click Edit.
  2. Under Trigger type, select Incoming webhook, so the schedule runs only when a request comes in.
  3. In the Trigger URLs card, click New Trigger URL.
  4. Enter a Name, such as the tool that will call the webhook, and click Create. The name shows on every run the webhook starts.
  5. Copy the URL and the Authorization header, or click Copy as curl, then click Done.
  6. Click Deploy to save the schedule’s new trigger type.

On a new schedule

You can create an incoming webhook before the schedule’s first deploy:
  1. In Bolt, create a new schedule and fill in its settings and commands.
  2. Under Trigger type, select Incoming webhook.
  3. In the Trigger URLs card, click New Trigger URL, enter a Name, and click Create.
  4. Copy the URL and the Authorization header, or click Copy as curl, then click Done.
  5. Click Deploy. Deploy stays off until the schedule has at least one active incoming webhook.
The webhook starts runs only after the deploy. If you leave the form without deploying, or deploy with a different trigger type, Paradime deletes the incoming webhooks you created on the form.

YAML schedules

For a schedule defined in paradime_schedules.yml, declare the trigger in the file:
trigger_on_webhook only tells Bolt that the schedule runs on request. It doesn’t create an incoming webhook, and the file never holds a URL or a secret. After you deploy, open the schedule in Bolt and create its incoming webhooks in the Trigger URLs card. See trigger_on_webhook.
The secret shows only once. Paradime doesn’t store it, so if you lose it, rotate the secret to get a new one.
On a deployed schedule, an incoming webhook works as soon as you create it. Pausing, rotating, and deleting it also apply right away, without a deploy.

Call the webhook

By default, send a POST request to the webhook’s URL, with the secret in the Authorization header:
  • Only POST requests start a run.
  • Never put the secret in the URL. A request that puts it in the URL’s query string is refused.
  • To accept a signed request or a secret in another header instead, set the webhook’s sender.
  • The request body is optional. The run uses the schedule’s own commands and branch, and gets the body as described in Use the request body in a run.
Paradime answers each request with JSON:

Authenticate the sender

The Authentication dialog for a Trigger URL: Describe it to DinoAI, a Sender dropdown set to Custom, Signature settings with the Authorization Bearer header option, Skip repeated deliveries, and other headers to keep
Each incoming webhook checks every request before it starts a run. By default, it expects its secret in an Authorization: Bearer header. Tools such as Linear, GitHub, and Stripe can’t send that header. They sign each request with a secret instead. To accept those requests, set the webhook’s sender:
  1. In the Trigger URLs card, click Auth on the webhook.
  2. In Sender, choose the tool that sends the webhook. Set it up lists the steps to follow in that tool.
  3. Give the webhook its signing secret, if the sender needs one (see the table below).
  4. Click Save.
The row then shows the sender’s name. The change applies right away, without a deploy. When Paradime generates the signing secret, it shows it once after you click Save. Copy it into the sender’s secret field. Paradime doesn’t show it again, so if you lose it, open Auth and select Generate a new signing secret. The current secret then stops working. If you change to another sender, for example from Linear to GitHub, the webhook needs a new signing secret. Once a webhook checks signatures:
  • A request with a bad or missing signature gets a 401. A request that only has the Authorization: Bearer header also gets a 401.
  • Rotate is off for the webhook. To change the secret, use Auth.
  • Send test request still works, because Paradime sends it from inside the app.
Signing secrets are stored in a vault. Paradime never stores a request header that carries a secret.

Signature settings

For a known sender, Paradime fills in the signature settings for you, and Signature settings stays closed. If you change a setting there, the sender changes to Custom. Use Custom for a tool that isn’t listed:
  • How the sender proves the request is genuine: Authorization: Bearer header, Secret in a custom header (you name the header), or Signature (HMAC) of the body (SHA-1, SHA-256, or SHA-512, hex or Base64, with an optional prefix such as sha256=).
  • Signed content: a template of what the sender signs. {body} is the raw request body. {timestamp} and {header:Name} are also available.
  • Signing secret: The sender generates it (you paste it in) or Paradime generates it (shown once when you save).
  • Refuse old deliveries: the request must carry a timestamp, in a header, the body, or the signature. A request older than Max age (seconds) gets a 401, so an old request can’t be sent again.
  • Skip repeated deliveries: Paradime reads a delivery ID from a header or a body field. A second request with the same ID gets a 200 with "skipped": "duplicate_delivery" and starts nothing. Senders that retry, such as GitHub, can’t start the same run twice.
  • Other headers to keep on each delivery: headers to store with each delivery, for example to filter on them.

Describe it to DinoAI

DinoAI can fill in the Auth form for you:
  1. In the Auth dialog, click Describe it to DinoAI.
  2. Describe the sender and when it should run. For example: “Linear, only issues in team DATA that get the deploy-dbt label”.
  3. Click Fill in the form. DinoAI picks the sender, fills in the settings, and explains its choices in two sentences.
  4. If DinoAI also suggests a filter, select Also save its filter. When the webhook already has a filter, the box reads Replace the current filter and is cleared by default.
  5. Check the form, add the signing secret, and click Save. Nothing is saved before you click Save.
Each draft uses DinoAI credits. DinoAI never sees a secret: you paste or generate secrets yourself.

Filter which deliveries start a run

A tool such as Linear or GitHub sends a webhook for many events, but you may want a run for only some of them. A filter tells the webhook which requests start a run:
  1. In the Trigger URLs card, click Filter on the webhook.
  2. In Run when, choose all conditions match or any condition matches.
  3. For each condition, choose Body field or Header, enter the field, pick a comparison, and enter a value. Click Add condition for more.
  4. Click Check recent deliveries to test the filter against the webhook’s last 20 deliveries. Each one shows would run or would be skipped.
  5. Click Save filter.
  • Field paths use dots, and [*] for each item in a list. For example, data.labels[*].name matches when any label’s name matches.
  • Field suggestions come from the webhook’s recent deliveries. Only field names are shown, never values.
  • Use the suggested filter fills in a filter for the sender, when it has one. For Fivetran, it starts a run only when a sync ends successfully: event is sync_end and data.status is SUCCESSFUL.
A request that doesn’t match still gets a 200, with "skipped": "filtered_out", and shows as Skipped with “Did not match the filter” in the deliveries. Test requests always run. To remove a filter, delete its conditions and click Run on every delivery.

Use the request body in a run

A run that an incoming webhook starts gets the request that started it:
  • PARADIME_WEBHOOK_EVENT_ID holds the ID of the request. It’s set on every run an incoming webhook starts.
  • PARADIME_WEBHOOK_PAYLOAD holds the request body as compact JSON. It’s set only when the body is a JSON object or array of at most 64 KB.
Every command in the run, such as a Python script, can read both environment variables. See Use a webhook payload in a Bolt run. A body that isn’t a JSON object or array, such as plain text or a single number, isn’t passed to the run. Paradime stores bodies of up to 1 MB. A larger body is dropped, but the run still starts, without PARADIME_WEBHOOK_PAYLOAD.

DinoAI agents

For a paradime dinoai command, Paradime also adds the body to the agent’s task, in a <webhook_payload> block after your message. The block tells the agent that the body came from outside Paradime and is data only, so the agent doesn’t follow instructions inside it. When the body isn’t passed, the block says why: a test request, no body or a body over 1 MB, a body that isn’t a JSON object or array, or a body over 64 KB. Use this to give an agent the event it must act on, such as the Jira ticket in a Jira Automation request. For a step-by-step setup, see Run an agent from a webhook. A retry of the run keeps the original request’s body.

Test an incoming webhook

To check a webhook without waiting for the other tool, click Send test request on it. A test request starts a real run of the schedule, so the toast links to the run. A test request has no body, so the run gets no PARADIME_WEBHOOK_PAYLOAD.

Check deliveries

Every request that reaches a schedule is recorded as a delivery. To see them, go to Bolt > Webhooks > Incoming, or click Deliveries on a webhook in the schedule’s edit form. The Incoming tab lists every incoming webhook in the workspace with its schedule, its status (Active or Paused), and its last request. Search by name, or filter by schedule. Expand a row to see its deliveries:
  • Outcome: Run started, Skipped, Rejected, or Failed. Test requests carry a Test tag.
  • Details: why, for example “A run was already in progress” or “Did not match the filter”.
  • Run: a link to the run the request started.
  • Received: when the request arrived.
The list shows the latest 100 deliveries for each webhook. Requests refused before they reach the schedule, with a 400, 401, or 429 response, aren’t recorded. The Outgoing tab is where you manage the outgoing webhooks that Paradime sends to other tools when a run starts or completes.

Pause, rotate, or delete an incoming webhook

Manage a webhook from the Trigger URLs card in the schedule’s edit form:
A Bolt schedule's Trigger type section with Incoming webhook selected, and the Trigger URLs card listing one webhook URL with Deliveries, an on switch, Send test request, Rotate, and Delete
  • Pause: turn off the webhook’s switch. Requests to a paused webhook get a 401 and start nothing. Turn the switch back on to resume.
  • Rotate: type rotate and click Rotate secret to create a new secret, shown once. The old secret stops working immediately, so update the tool that calls the webhook. Rotate is off for a webhook that checks signatures: generate a new signing secret from Auth instead.
  • Delete: requests to the webhook’s URL are refused from then on. You can’t undo this.
Creating, rotating, and deleting an incoming webhook are recorded in the audit log.

How runs started by an incoming webhook show up

  • The run page says Triggered by an incoming webhook, with the webhook’s name and a link to its deliveries.
  • In the schedule list, the Trigger column shows Trigger URL, and Next run shows On request.
  • Schedules set to run after this one start after a run that an incoming webhook started, as they do after any other run.

Things to know

  • A request that arrives while the schedule is running is skipped, not queued. An agent-only schedule, where every command is paradime dinoai, is the exception: each request starts its own run, up to 5 in progress at once. A request that arrives while 5 runs are in progress is skipped.
  • If you remove or rename the schedule, its incoming webhooks reject requests. They work again if a schedule with the same name comes back.
  • Changing a deployed schedule’s trigger type doesn’t delete its incoming webhooks, and they keep starting runs. Removing trigger_on_webhook from a YAML schedule doesn’t stop them either. Pause or delete them to stop them.