Skip to main content

SET UP WEBHOOKS

Prerequisites: Swamp installed, a repository with a workflow, familiarity with swamp serve. See swamp serve how-to guides for server setup.

Start the server with a GitHub webhook

The --webhook flag registers an HTTP endpoint that triggers a workflow when it receives a POST request. The format is <route>:<workflow>:<secret>[:<scheme>[:<header>[:<prefix>]]].

swamp serve --webhook '/hooks/github:deploy-pipeline:mysecret'

The server validates the request signature using the X-Hub-Signature-256 header (HMAC-SHA256) before triggering the workflow.

Test locally with curl

Compute the HMAC signature and send a test request:

SECRET="mysecret"
BODY='{"ref":"refs/heads/main"}'
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print "sha256="$2}')

curl -X POST http://localhost:9090/hooks/github \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: $SIG" \
  -d "$BODY"

Use an environment variable for the secret

To avoid putting secrets in command arguments:

swamp serve --webhook '/hooks/github:deploy-pipeline:@env=WEBHOOK_SECRET'

Use a file-based secret

swamp serve --webhook '/hooks/github:deploy-pipeline:@file=/run/secrets/webhook'

Use a vault-managed secret

Store the secret in a vault, then reference it with @vault=<name>:<key>:

swamp serve --webhook '/hooks/github:deploy-pipeline:@vault=prod-secrets:webhook-key'

Any configured vault backend works. See the vaults reference for vault setup and the secret source explanation for when to choose vaults over environment variables or files.

Set up a Linear webhook

Use the linear scheme. Linear sends a signature in the Linear-Signature header:

swamp serve --webhook '/hooks/linear:triage-workflow:@env=LINEAR_SECRET:linear'

Set up a Stripe webhook

Use the stripe scheme. Stripe uses the Stripe-Signature header with timestamp-based signatures:

swamp serve --webhook '/hooks/stripe:billing-workflow:@env=STRIPE_WEBHOOK_SECRET:stripe'

Set up a Jira webhook

Use the jira scheme. Jira sends a signature in the X-Hub-Signature header with a sha256= prefix:

swamp serve --webhook '/hooks/jira:on-issue:@env=JIRA_WEBHOOK_SECRET:jira'

Set up a generic webhook

For services that send a static token in a custom header, use the generic scheme. Specify the header name and optional value prefix:

swamp serve --webhook '/hooks/custom:my-workflow:mytoken:generic:X-Api-Key'

If the service sends the token with a prefix (e.g., Bearer mytoken):

swamp serve --webhook '/hooks/custom:my-workflow:mytoken:generic:Authorization:Bearer '

Access webhook payload in workflow CEL

Inside a workflow step, the webhook payload is available through CEL expressions:

  • webhook.headers — request headers
  • webhook.body — parsed JSON body
  • webhook.params — URL query parameters

Correlate webhook-triggered runs with your traces

Webhook requests automatically propagate W3C traceparent and tracestate headers into the triggered workflow execution. Include these headers in your webhook request to make the swamp run appear as a child span of your trace:

curl -X POST http://localhost:9090/hooks/github \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: $SIG" \
  -H "traceparent: 00-abcd1234abcd1234abcd1234abcd1234-abcd1234abcd1234-01" \
  -d "$BODY"

No additional configuration is needed on the swamp serve side.

Receive Telegram bot updates

Use the @swamp/telegram extension scheme to receive Telegram bot updates. Telegram uses a static secret token in the X-Telegram-Bot-Api-Secret-Token header — weaker than HMAC, so TLS is required.

1. Configure serve.yaml

webhooks:
  - route: /hooks/telegram
    workflow: on-telegram
    secret: "@env=TELEGRAM_BOT_SECRET"
    scheme: "@swamp/telegram"

2. Register the webhook with Telegram

curl -X POST "https://api.telegram.org/bot$BOT_TOKEN/setWebhook" \
  -d "url=https://swamp.example.com/hooks/telegram" \
  -d "secret_token=$TELEGRAM_BOT_SECRET"

The secret_token must match the secret configured in serve.yaml. Telegram sends it back in every update request for the server to verify.

3. Access the update in your workflow

Use CEL expressions to read the Telegram update payload:

steps:
  - name: handle-message
    task:
      type: model_method
      modelIdOrName: telegram-handler
      methodName: process
      inputs:
        chatId: "${{ webhook.body.message.chat.id }}"
        text: "${{ webhook.body.message.text }}"

Security caveats

  • The secret is transmitted in the clear as a header value, not derived from the request body. Always serve over HTTPS.
  • The handler uses constant-time comparison to prevent timing attacks.
  • Do not use @swamp/telegram over plain HTTP — any intermediary can read the secret.

Use an extension webhook scheme

Extension webhook schemes (@collective/name) provide custom verification logic for services not covered by the built-in schemes. Extensions are auto-pulled from trusted collectives on first reference.

webhooks:
  - route: /hooks/custom
    workflow: on-custom-event
    secret: "@env=CUSTOM_SECRET"
    scheme: "@acme/my-webhook"
    config:
      challengeField: challenge

The config object is passed to the extension handler. See the webhooks reference for the handler lifecycle and the manifest reference for how to author a webhook extension.

For the full --webhook flag specification, run swamp help serve.