Pack triggers
The webhook, poll and schedule triggers packs provide, how a routine subscribes to one, and how B3OS verifies, deduplicates and delivers their events.
A pack trigger turns something that happens in another service into an event: a GitHub issue opened, a Stripe invoice paid, a new row since the last poll. Routines consume the events, each one starting a run.
Kinds
| Kind | How events arrive |
|---|---|
webhook | The service posts to a B3OS hook URL that the pack registers for you; B3OS verifies the signature, deduplicates and filters |
poll | B3OS calls a pack action on an interval and keeps a cursor, so each item becomes one event |
schedule | B3OS calls a pack action on a schedule and turns the result into an event |
GET /v1/actions/triggers lists the triggers packs provide, with each one's configuration schema and event schema:
bashcurl -s -G https://beta-api.b3os.org/v1/actions/triggers \ -H "Authorization: Bearer $B3OS_API_KEY" -d pack=io.b3os/github
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();for await (const trigger of b3os.actions.listTriggers({ pack: "io.b3os/github" })) { console.log(trigger.ref, trigger.kind, trigger.title);}
pythonfrom b3os import B3OSb3os = B3OS()for trigger in b3os.actions.list_triggers(pack="io.b3os/github").auto_paging_iter(): print(trigger["ref"], trigger["kind"], trigger["title"])
The MCP tools cover actions, not triggers: actions_search finds actions only. Subscribing is part of publishing a routine, which happens from code or the CLI.
Subscribe from a routine
Add a type: action trigger to a routine and publish it:
yamlname: triage-new-issuestriggers: - type: action id: issue_opened uses: io.b3os/github/issue-opened@1 with: owner: acme repo: web connections: api: conn_01m5t6cbgdjs1ketgcqwa2sne8steps: - id: label uses: infer/chat@1 with: model: ${{ vars.model }} messages: - role: user content: "Suggest one label for this issue: ${{ trigger.data.title }}"vars: model: b3os/your-chat-model
Publishing creates a trigger subscription (tsub_) for each action trigger. Each event that passes the trigger's if starts a run as the key that published the version, with the event in trigger.data (valid against the trigger's event schema) and its ID in trigger.event_id. Delivery is at least once, and a repeated event ID on the same subscription starts nothing. Routine triggers has every field.
Subscriptions
Subscriptions are read-only. You change one by publishing the routine:
- a new version updates its subscriptions, and removes those of action triggers it no longer has;
- a rollback makes the earlier version's triggers current, adding, updating and removing subscriptions to match;
- deleting the routine removes all of them.
GET /v1/actions/subscriptions lists them, filterable by routine or pack:
bashcurl -s -G https://beta-api.b3os.org/v1/actions/subscriptions \ -H "Authorization: Bearer $B3OS_API_KEY" -d pack=io.b3os/github
tsfor await (const sub of b3os.actions.listSubscriptions({ pack: "io.b3os/github" })) { console.log(sub.id, sub.status, sub.last_event_at, sub.error?.detail);}
pythonfor sub in b3os.actions.list_subscriptions(pack="io.b3os/github").auto_paging_iter(): print(sub["id"], sub["status"], sub["last_event_at"], sub["error"]["detail"] if sub["error"] else None)
No MCP tool reads subscriptions. Check them from code, or with b3os api GET /v1/actions/subscriptions.
GET /v1/actions/subscriptions/{subscription_id} shows one: the exact trigger version, its configuration and connections, the hook it registered, when the last event arrived, and its status. active subscriptions receive events. paused ones drop events while the routine's triggers are paused, for example because its publishing key was revoked. failed means subscribing at the service failed; error says why, and B3OS retries.
Webhook verification
Webhook triggers verify each delivery with the scheme the pack declares (GitHub, Stripe, Slack, Standard Webhooks, or a generic timestamped HMAC), comparing signatures in constant time over the raw body. Timestamped schemes refuse deliveries more than 300 seconds from the node's clock, with webhook_signature_invalid and reason timestamp. Services that send a verification handshake, such as Slack's url_verification, get the answer the pack defines.
The inbound URL for webhook triggers, POST /v1/actions/hooks/{hook_id}, is planned for later in the beta. Until a node serves it, webhook triggers cannot receive deliveries; poll and schedule triggers do not need it, and neither do routine webhook triggers, which have their own URL (/v1/routines/hooks/{hook_id}).