Skip to main content

Webhooks

A webhook is an inbound endpoint. An external system — GitHub, GitLab, Jira, Bitbucket, or anything that can send an HTTP POST — sends events to its URL, and FYAI starts a run of the webhook's linked workflow for each event that passes the webhook's filters.

Webhooks belong to a project. Manage them in Settings → Webhooks (under Project).

How a delivery is handled​

POST to webhook URL
│
├─ unknown URL ............................ 404
├─ webhook disabled ....................... 410
├─ signature missing or wrong ............. 401 (see "Signing")
├─ repeat of a delivery already run ....... 409 (GitHub / GitLab delivery ID)
│
├─ work out the event type
├─ check event filters ── no match ........ 200 "filtered"
├─ duplicate suppression ── duplicate ..... 200 "deduplicated"
│
└─ start a mission from the Linked Workflow
├─ started .......................... 200 "accepted"
└─ could not start .................. error code (for example 423 if the
workflow is deactivated, 502 if the
run could not be handed over)

Every delivery — including rejected ones — is written to the webhook's delivery log. The receiver accepts up to 120 requests a minute from one source IP address.

The response body tells the sender what happened:

{
"status": "accepted",
"event_type": "github.pull_request.opened",
"matched": true,
"match_details": "PASS: event_type equals github.pull_request.opened [mission=123]",
"error": null
}

status is accepted, filtered, deduplicated or error.

Webhook settings​

FieldDescription
NameRequired.
ProviderGitHub, GitLab, Jira, Bitbucket, Slack or Custom. Decides how deliveries are signed and which filter shortcuts are offered.
DescriptionOptional.
Linked WorkflowThe workflow to run. None accepts and logs deliveries without running anything.
Active / DisabledA disabled webhook answers every delivery with 410.
TagsComma-separated.
Event filtersRules a delivery must pass. See below.
Duplicate suppressionOptional. See below.

After saving, the ENDPOINT box shows POST and the webhook URL (with Copy URL), and the start of the signing secret (with Copy Secret). The list shows each webhook's provider, how many times it has triggered, and Active or Disabled.

The URL contains a long random token. Anyone with the URL can post to it, so treat it as a secret.

Signing​

Every webhook gets a signing secret when it is created. Regen Secret replaces it ("Existing integrations using the old secret will break").

ProviderWhat FYAI checks
GitHubThe X-Hub-Signature-256 HMAC-SHA256 signature (or the older X-Hub-Signature SHA-1) made with the secret. A delivery without a signature is rejected.
GitLabThe X-Gitlab-Token header must equal the secret. A delivery without it is rejected.
Jira, Bitbucket, Slack, CustomThe URL token alone authenticates the delivery. If the delivery does carry a GitHub or GitLab signature header, it must be valid.

For GitHub and GitLab, a signed delivery whose delivery ID (X-GitHub-Delivery or X-Gitlab-Event-UUID) already started a run in the last 5 minutes is rejected as a replay (409).

Event types​

FYAI derives an event type from each delivery, which you can filter on:

SourceEvent type
GitHub (X-GitHub-Event header)github.<event>.<action>, for example github.pull_request.opened, or github.<event> when there is no action, for example github.push
GitLab (X-Gitlab-Event header)gitlab. + the header in lower case with underscores, for example gitlab.push_hook, gitlab.merge_request_hook
Jira (webhookEvent in the body)jira.<webhookEvent>, for example jira.jira:issue_created
Bitbucket (X-Event-Key header)bitbucket.<key>, for example bitbucket.repo:push
Anything elseThe body's event_type field, or the X-Event-Type header

Event filters​

Click Add Filter to add a rule, or click a provider shortcut chip (for example Push, PR Opened, PR Closed for GitHub). With no filters, "all events will be accepted".

Each rule has a Field, an Operator and a Value. A delivery must pass every rule.

Field can be:

FieldReads
event_typeThe derived event type.
payload.<path>A value in the JSON body, by dotted path. Numbers index into lists, for example payload.commits.0.id.
header.<name>A request header, for example header.x-github-event.
<key>A top-level key in the JSON body.

Operators: Equals, Not Equals, Contains, Starts With, Ends With, Exists (no value), Regex. A rule whose field is missing from the delivery fails.

Through the API, a rule can instead be a group — {"any_of": [...]} or {"all_of": [...]} of nested rules — to express "this OR that".

Duplicate suppression​

Senders often fire several events for one piece of work: GitHub sends check_suite.completed once per check suite, so one commit can wake a workflow three times. Turn on DUPLICATE SUPPRESSION to stop a second run starting while the first is still going.

SettingDescription
Key fieldPayload paths that identify the piece of work. The values found are joined into a key; paths missing from a delivery are skipped. Click Add Key Field for more.
Window (seconds)How far back to look. Default 600.
Preset chipGitHub, GitLab and Bitbucket offer One run per commit; Jira offers One run per change.

A delivery is suppressed only while a run started by an earlier delivery with the same key is still in progress and within the window. Once that run finishes, the next event starts a fresh run. If no key field resolves, the delivery runs normally. Choose fields that change when the work changes (a commit SHA rather than a pull request number).

Suppressed deliveries are logged and answered with deduplicated. Through the API you can also set deferral rules, which record each suppressed delivery in the workflow's run state so a later run can pick it up.

Delivery log​

Select a webhook and click Logs to see RECENT DELIVERIES: when each arrived, its event type, Matched or No match, and the response code returned. The API returns the full headers, payload and match details for each delivery (GET /webhooks/{id}/logs).

What the workflow receives​

A webhook run's initial message is built from the event:

Triggered by webhook event: github.pull_request.opened

<short summary of the key fields, e.g. repository, pull request, action>

Raw event payload:
{ ...the JSON body, cut at 4,000 characters... }

Agents and functions with an empty input message receive this text, and any node can insert it with ${initial_message}. Webhook runs get no attribute values. The run is recorded with Trigger shown as Webhook.

Webhooks and data sources​

A webhook can also deliver its payloads to a data source instead of, or as well as, a workflow. This target (data_source_id) is set through the API.