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
- Add the Webhook block — drag it onto the canvas as the workflow's start block.
- Open Webhook Configuration — the block shows a configuration panel with a generated URL and auth options.
- Copy the webhook URL — a unique path per workflow, e.g.
https://mybotbox.com/api/webhooks/trigger/<path>. - Configure authentication — pick one of the 4 modes below.
- Generate a test URL (optional) — a 24-hour scratch URL that hits your canvas state without redeploying.
- 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 namedmessage<webhook1.data.key>— a nested field
Authentication
The Webhook trigger supports four authentication modes, selected per-trigger in the configuration panel:
| Mode | What the caller sends | Use when |
|---|---|---|
none | no auth header | internal tools behind another gateway, or purely public events |
bearer | Authorization: Bearer <token> | programmatic callers, API clients |
custom_header | <configured-name>: <token> | matching legacy conventions (e.g. X-API-Key) |
hmac_sha256 | X-Signature: <hex> over raw body | strongest — 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:
X-Idempotency-Key(orIdempotency-Key) request header- Top-level
idfield in the JSON body - 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
- Drop a service block — e.g. Slack, GitHub, Airtable.
- Toggle trigger mode — the block's "Trigger Configuration" panel replaces the action config.
- Select credential — service blocks use OAuth where applicable.
- Configure event filters — where the provider supports them (e.g. GitHub event types).
- 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 service | The service has a dedicated block |
| Payload shape is custom or internal | You want provider signature verification |
| No existing integration covers it | You want event-type filtering built in |
Supported services for trigger mode
Blocks registered with a trigger (from apps/sat/triggers/index.ts):
- Slack — messages, mentions, reactions
- GitHub — push, PR, issue events
- Airtable — record changes
- Stripe — billing events
- Telegram — bot messages and commands
- WhatsApp — messaging events
- Microsoft Teams —
@-mentions in channels - Circleback — meeting notes, action items, transcripts
- Google Forms — response submissions (Apps Script forwarder)
- Gmail — OAuth poller
- Outlook — OAuth poller
- IMAP — generic mailbox poller
- Google Tasks — task list poller
- RSS — feed poller
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
replayWindowSecondsto 300 or less with HMAC. - Keep
enableIdempotencyon for event-driven integrations. - Rotate
token/hmacSecretquarterly; 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