> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# 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:

**curl**

```bash
    curl -s -G https://beta-api.b3os.org/v1/actions/triggers \
      -H "Authorization: Bearer $B3OS_API_KEY" -d pack=io.b3os/github
    ```
  **TypeScript**

```ts
    import { 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);
    }
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    for trigger in b3os.actions.list_triggers(pack="io.b3os/github").auto_paging_iter():
        print(trigger["ref"], trigger["kind"], trigger["title"])
    ```
  **MCP**

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:

```yaml
name: triage-new-issues
triggers:
  - type: action
    id: issue_opened
    uses: io.b3os/github/issue-opened@1
    with:
      owner: acme
      repo: web
    connections:
      api: conn_01m5t6cbgdjs1ketgcqwa2sne8
steps:
  - 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](/routines/triggers#pack-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:

**curl**

```bash
    curl -s -G https://beta-api.b3os.org/v1/actions/subscriptions \
      -H "Authorization: Bearer $B3OS_API_KEY" -d pack=io.b3os/github
    ```
  **TypeScript**

```ts
    for await (const sub of b3os.actions.listSubscriptions({ pack: "io.b3os/github" })) {
      console.log(sub.id, sub.status, sub.last_event_at, sub.error?.detail);
    }
    ```
  **Python**

```python
    for 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)
    ```
  **MCP**

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`](/errors#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}`).