MyBotBoxMyBotBox

Webhooks

Trigger workflows from external HTTP requests with configurable authentication and deduplication.

Webhooks let external services trigger a workflow by sending an HTTP request to a MyBotBox-hosted URL. MyBotBox supports two approaches: a generic webhook trigger for any service, and trigger mode on service-specific blocks (Slack, GitHub, etc.) for built-in event filtering.

If your caller sends natural language prompts + context instead of structured JSON fields, use the API Prompt trigger instead.

Generic Webhook Trigger

The Webhook block (in the Triggers category) creates a flexible endpoint that accepts any JSON payload and starts the workflow.

Demo: dropping the Webhook block onto a workflow, configuring auth + idempotency, and copying the generated trigger URL. (Video coming soon.)

How it works

  1. Add the Webhook block — drag it onto the canvas as the workflow's start block.
  2. Open Webhook Configuration — the block shows a configuration panel with a generated URL and auth options.
  3. Copy the webhook URL — a unique path per workflow, e.g. https://mybotbox.com/api/webhooks/trigger/<path>.
  4. Configure authentication — pick one of the 4 modes below.
  5. Generate a test URL (optional) — a 24-hour scratch URL that hits your canvas state without redeploying.
  6. Send a request from your external service — any POST to the URL triggers the workflow (assuming auth + rate limits pass).

Payload access

Webhook data is injected into the workflow context under the block's output name. If the block is named webhook1, the POSTed JSON is available via dot notation in downstream blocks:

  • <webhook1.message> — a top-level field named message
  • <webhook1.data.key> — a nested field

Authentication

The Webhook trigger supports four authentication modes, selected per-trigger in the configuration panel:

ModeWhat the caller sendsUse when
noneno auth headerinternal tools behind another gateway, or purely public events
bearerAuthorization: Bearer <token>programmatic callers, API clients
custom_header<configured-name>: <token>matching legacy conventions (e.g. X-API-Key)
hmac_sha256X-Signature: <hex> over raw bodystrongest — tamper-proof, no shared-secret-in-header

Bearer token

Set authMode: bearer + token: <value>. Caller sends:

curl -X POST https://mybotbox.com/api/webhooks/trigger/<path> \
  -H 'Authorization: Bearer $WEBHOOK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"message":"hello"}'

Custom header

Set authMode: custom_header + secretHeaderName: X-API-Key + token: <value>:

curl -X POST https://mybotbox.com/api/webhooks/trigger/<path> \
  -H 'X-API-Key: $WEBHOOK_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"message":"hello"}'

HMAC-SHA256

Set authMode: hmac_sha256 + hmacSecret: <shared-secret>. Default signature header is X-Signature. The caller computes HMAC-SHA256 over the exact raw request body using the shared secret and sends the hex digest.

BODY='{"message":"hello"}'
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" | cut -d' ' -f2)

curl -X POST https://mybotbox.com/api/webhooks/trigger/<path> \
  -H "X-Signature: $SIG" \
  -H 'Content-Type: application/json' \
  -d "$BODY"
import { createHmac } from 'node:crypto'

const body = JSON.stringify({ message: 'hello' })
const signature = createHmac('sha256', process.env.HMAC_SECRET)
  .update(body)
  .digest('hex')

await fetch(`https://mybotbox.com/api/webhooks/trigger/${path}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-Signature': signature },
  body,
})

```text
</Tab>
<Tab value="Python">
```python
import hmac, hashlib, json, requests

body = json.dumps({"message": "hello"}).encode()
signature = hmac.new(HMAC_SECRET.encode(), body, hashlib.sha256).hexdigest()

requests.post(
    f"https://mybotbox.com/api/webhooks/trigger/{path}",
    data=body,
    headers={"Content-Type": "application/json", "X-Signature": signature},
)

The platform also accepts signatures with a sha256= prefix (GitHub convention) for compatibility.

Sign the exact bytes you send on the wire, not a re-stringified JSON object. Re-serializing with different whitespace/key order invalidates the signature.

Replay protection

HMAC mode supports an optional timestamp window. Enable by setting replayWindowSeconds (default 300, set 0 to disable). The caller must include X-Timestamp as unix seconds or ISO-8601:

TS=$(date +%s)
BODY='{"message":"hello"}'
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" | cut -d' ' -f2)

curl -X POST https://mybotbox.com/api/webhooks/trigger/<path> \
  -H "X-Signature: $SIG" \
  -H "X-Timestamp: $TS" \
  -H 'Content-Type: application/json' \
  -d "$BODY"

Requests older than the window return 401.

Idempotency

When enableIdempotency is on (default), duplicate requests return 200 { status: "duplicate" } without re-running the workflow. The dedup key is derived in this order:

  1. X-Idempotency-Key (or Idempotency-Key) request header
  2. Top-level id field in the JSON body
  3. SHA-256 of the raw body

Dedup window is 7 days. As of migration 0109 the platform also writes (webhook_id, provider_event_id) rows into webhook_event_dedup with a unique index — defense-in-depth at the storage layer on top of the Redis cache. See the database changelog for the table definition.

curl -X POST https://mybotbox.com/api/webhooks/trigger/<path> \
  -H 'X-Idempotency-Key: order-12345-attempt-1' \
  -H 'Content-Type: application/json' \
  -d '{"order":"12345"}'

Rate limits

Each webhook path is limited to 100 requests/minute by default (configurable per-trigger via rateLimitPerMinute). Exceeding the limit returns 429 with a Retry-After header. IP-level or subscription-tier workflow limits apply on top.

IP allowlist

For additional defense-in-depth, set allowedIps to a comma-separated list. Requests from other IPs return 401.

Trigger Mode for Service Blocks

Service-specific blocks support trigger mode, where the block becomes the workflow's start instead of an action. Each service registers a provider-specific webhook and handles signature verification automatically.

Demo: enabling trigger mode on a Slack block — selecting an OAuth credential and choosing the events to fire on (messages, mentions, reactions). (Video coming soon.)

Setup

  1. Drop a service block — e.g. Slack, GitHub, Airtable.
  2. Toggle trigger mode — the block's "Trigger Configuration" panel replaces the action config.
  3. Select credential — service blocks use OAuth where applicable.
  4. Configure event filters — where the provider supports them (e.g. GitHub event types).
  5. Save — MyBotBox registers the webhook with the external provider, or surfaces the URL you paste into the provider's dashboard.

When to use which

Use Generic Webhook when…Use Trigger Mode when…
You control the calling serviceThe service has a dedicated block
Payload shape is custom or internalYou want provider signature verification
No existing integration covers itYou want event-type filtering built in

Supported services for trigger mode

Blocks registered with a trigger (from apps/sat/triggers/index.ts):

Verify with the bundled scripts

Every webhook provider ships a matched pair of verify.ts (Bun) + verify.py (Python) scripts under apps/sat/tests/staging/triggers/<provider>/. They POST a provider-shaped sample payload (mirroring the trigger's samplePayload declaration) at the deployed webhook URL and report whether the trigger ACKed 200. Both variants are stdlib-only — no install step.

# Generic webhook (HMAC-SHA256 mode)
bun apps/sat/tests/staging/triggers/generic/verify.ts \
  https://mybotbox.com/api/webhooks/trigger/<path> \
  --secret=<hmac-secret>

See the README for the per-trigger flag matrix (Slack signing secret, GitHub HMAC secret, Stripe whsec_, Teams base64 token, Telegram secret token, WhatsApp App Secret, etc.).

Security checklist

  • Use HMAC-SHA256 for anything production-critical.
  • Set replayWindowSeconds to 300 or less with HMAC.
  • Keep enableIdempotency on for event-driven integrations.
  • Rotate token / hmacSecret quarterly; changing them is a single-save operation.
  • Never commit webhook URLs to public repositories — the path is the only unguessable piece for public endpoints.

Common use cases

  • CI/CD — GitHub push triggers deploy workflow
  • Notifications — Slack message triggers automated reply
  • Data sync — Airtable record change fans out to other systems
  • Support — ticket creation triggers routing / escalation
  • Commerce — Stripe event triggers fulfillment or alerting