<!-- Generated by `just docs` from proto/automaton/v1/triggers.proto. Edit the source, not this file. -->

# TriggersService

The inbound direction: an external app has something happen, and you hear about it. Subscribe an address, read what arrived, and replay a delivery your side missed. Delivery is at least once, with retries and a dead state, and every attempt is readable here.

Every call is a POST to `https://api.atmon.ai/automaton.v1.TriggersService/<Call>` with a JSON body, and authenticates with `Authorization: Bearer <your project key>`. Field names in JSON are lowerCamelCase, so the field written `tool_slug` below is `toolSlug` on the wire. [How to call the API](./index.md) has the whole convention.

## Calls

| Call | Request | Response | Summary |
| --- | --- | --- | --- |
| `CreateSubscription` | `CreateSubscriptionRequest` | `CreateSubscriptionResponse` | Registers an endpoint for delivery and returns its signing secret once. |
| `ListSubscriptions` | `ListSubscriptionsRequest` | `ListSubscriptionsResponse` | Lists the project's subscriptions. |
| `DeleteSubscription` | `DeleteSubscriptionRequest` | `DeleteSubscriptionResponse` | Deletes one subscription. |
| `ListEvents` | `ListEventsRequest` | `ListEventsResponse` | Lists the normalized events received for this project, filtered by toolkit, trigger, and time. |
| `GetEvent` | `GetEventRequest` | `GetEventResponse` | Reads one event with its normalized payload. |
| `ListDeliveries` | `ListDeliveriesRequest` | `ListDeliveriesResponse` | Lists delivery attempts for an event, a subscription, or both. |
| `ReplayEvent` | `ReplayEventRequest` | `ReplayEventResponse` | Queues fresh deliveries for an event to the currently matching active subscriptions, leaving the original attempt history in place so the record of what failed stays readable. |
| `ListIngestEndpoints` | `ListIngestEndpointsRequest` | `ListIngestEndpointsResponse` | Lists every toolkit that declares an inbound webhook, with the path a provider posts to and whether this deployment holds the secret that verifies it. |

### CreateSubscription

Registers an endpoint for delivery and returns its signing secret once.
HTTPS is required outside loopback.

Request `CreateSubscriptionRequest`, response `CreateSubscriptionResponse`.

```http
POST /automaton.v1.TriggersService/CreateSubscription HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "endpointUrl": "...",
  "toolkitSlug": "...",
  "triggerSlug": "..."
}
```

The response:

```json
{
  "subscription": {
    "id": "...",
    "endpointUrl": "...",
    "toolkitSlug": "...",
    "triggerSlug": "...",
    "active": true
  },
  "signingSecret": "..."
}
```

### ListSubscriptions

Lists the project's subscriptions. A signing secret is never returned
again, so a lost secret means a new subscription.

Request `ListSubscriptionsRequest`, response `ListSubscriptionsResponse`.

```http
POST /automaton.v1.TriggersService/ListSubscriptions HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{}
```

The response:

```json
{
  "subscriptions": [{
    "id": "...",
    "endpointUrl": "...",
    "toolkitSlug": "...",
    "triggerSlug": "...",
    "active": true
  }]
}
```

### DeleteSubscription

Deletes one subscription. Events already stored are unaffected.

Request `DeleteSubscriptionRequest`, response `DeleteSubscriptionResponse`.

```http
POST /automaton.v1.TriggersService/DeleteSubscription HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "id": "..."
}
```

The response:

```json
{}
```

### ListEvents

Lists the normalized events received for this project, filtered by toolkit,
trigger, and time.

Request `ListEventsRequest`, response `ListEventsResponse`.

```http
POST /automaton.v1.TriggersService/ListEvents HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "toolkitSlug": "...",
  "triggerSlug": "...",
  "since": "2026-01-31T09:15:00Z",
  "until": "2026-01-31T09:15:00Z",
  "pageSize": 0,
  "pageToken": "..."
}
```

The response:

```json
{
  "events": [{
    "id": "...",
    "toolkitSlug": "...",
    "triggerSlug": "...",
    "entityId": "...",
    "payloadJson": "{}",
    "occurredAt": "2026-01-31T09:15:00Z",
    "receivedAt": "2026-01-31T09:15:00Z"
  }],
  "nextPageToken": "..."
}
```

### GetEvent

Reads one event with its normalized payload.

Request `GetEventRequest`, response `GetEventResponse`.

```http
POST /automaton.v1.TriggersService/GetEvent HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "id": "..."
}
```

The response:

```json
{
  "event": {
    "id": "...",
    "toolkitSlug": "...",
    "triggerSlug": "...",
    "entityId": "...",
    "payloadJson": "{}",
    "occurredAt": "2026-01-31T09:15:00Z",
    "receivedAt": "2026-01-31T09:15:00Z"
  }
}
```

### ListDeliveries

Lists delivery attempts for an event, a subscription, or both. Delivery is
at-least-once: pending, delivered, or dead_letter after the last retry.

Request `ListDeliveriesRequest`, response `ListDeliveriesResponse`.

```http
POST /automaton.v1.TriggersService/ListDeliveries HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "eventId": "...",
  "subscriptionId": "..."
}
```

The response:

```json
{
  "deliveries": [{
    "id": "...",
    "eventId": "...",
    "subscriptionId": "...",
    "state": "...",
    "attempts": 0,
    "lastError": "...",
    "lastAttemptAt": "2026-01-31T09:15:00Z"
  }]
}
```

### ReplayEvent

Queues fresh deliveries for an event to the currently matching active
subscriptions, leaving the original attempt history in place so the record
of what failed stays readable.

Request `ReplayEventRequest`, response `ReplayEventResponse`.

```http
POST /automaton.v1.TriggersService/ReplayEvent HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "eventId": "..."
}
```

The response:

```json
{
  "deliveries": [{
    "id": "...",
    "eventId": "...",
    "subscriptionId": "...",
    "state": "...",
    "attempts": 0,
    "lastError": "...",
    "lastAttemptAt": "2026-01-31T09:15:00Z"
  }]
}
```

### ListIngestEndpoints

Lists every toolkit that declares an inbound webhook, with the path a
provider posts to and whether this deployment holds the secret that
verifies it. A read of deployment configuration rather than of project
rows: the answer is the same for every project on the node, and it is here
because the page that asks "what starts this" is the page that has to say
when the answer is nothing.

Request `ListIngestEndpointsRequest`, response `ListIngestEndpointsResponse`.

```http
POST /automaton.v1.TriggersService/ListIngestEndpoints HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{}
```

The response:

```json
{
  "endpoints": [{
    "toolkitSlug": "...",
    "path": "...",
    "scheme": "...",
    "secretEnv": "...",
    "secretSet": true
  }]
}
```

## Messages

### CreateSubscriptionRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `endpoint_url` | `string` | 1 |  |
| `toolkit_slug` | `string` | 2 | empty subscribes to every toolkit |
| `trigger_slug` | `string` | 3 | requires toolkit_slug; empty takes every trigger |

### CreateSubscriptionResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `subscription` | `Subscription` | 1 |  |
| `signing_secret` | `string` | 2 | signing_secret is returned once, at creation. atmon signs every delivery body with it (X-Automaton-Signature: sha256=<hex>); a lost secret is replaced by a new subscription, never recovered. |

### DeleteSubscriptionRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `id` | `string` | 1 |  |

### DeleteSubscriptionResponse

No fields. The call takes its scope from the authenticated project.

### Delivery

Delivery is one attempt series: one event to one subscription.

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `id` | `string` | 1 |  |
| `event_id` | `string` | 2 |  |
| `subscription_id` | `string` | 3 |  |
| `state` | `string` | 4 | pending \| delivered \| dead_letter |
| `attempts` | `int32` | 5 |  |
| `last_error` | `string` | 6 |  |
| `last_attempt_at` | `google.protobuf.Timestamp` | 7 |  |

### Event

Event is one normalized inbound event, stored per receiving project.

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `id` | `string` | 1 |  |
| `toolkit_slug` | `string` | 2 |  |
| `trigger_slug` | `string` | 3 | the toolkit's kind: trigger tool |
| `entity_id` | `string` | 4 | empty when the payload does not resolve one |
| `payload_json` | `string` | 5 | normalized body per the trigger's output schema |
| `occurred_at` | `google.protobuf.Timestamp` | 6 | provider time when present, else received_at |
| `received_at` | `google.protobuf.Timestamp` | 7 |  |

### GetEventRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `id` | `string` | 1 |  |

### GetEventResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `event` | `Event` | 1 |  |

### IngestEndpoint

IngestEndpoint is one toolkit's inbound path and whether this deployment can
verify a post to it.

The secret itself is never on this message and there is no RPC that returns
it. What crosses is whether the environment variable naming it holds a value,
because that single bit decides between a post being accepted and a post
being refused, and an operator has no other way to read it.

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `toolkit_slug` | `string` | 1 |  |
| `path` | `string` | 2 | The path a provider posts to, which is /webhooks/ plus the toolkit slug. |
| `scheme` | `string` | 3 | The verification scheme the toolkit declares, from the catalog's closed vocabulary: hmac_sha256, slack_v0, token_query. |
| `secret_env` | `string` | 4 | The name of the process environment variable holding the shared secret. The name is configuration and is safe to render; the value is not returned. |
| `secret_set` | `bool` | 5 | False means every post to this path is refused rather than trusted, so the toolkit's triggers fire nothing until the deployment sets the variable. |

### ListDeliveriesRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `event_id` | `string` | 1 | filter by event, subscription, or both |
| `subscription_id` | `string` | 2 |  |

### ListDeliveriesResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `deliveries` | repeated `Delivery` | 1 |  |

### ListEventsRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `toolkit_slug` | `string` | 1 | empty lists every toolkit |
| `trigger_slug` | `string` | 2 | empty lists every trigger |
| `since` | `google.protobuf.Timestamp` | 3 | inclusive lower bound on received_at |
| `until` | `google.protobuf.Timestamp` | 4 | exclusive upper bound on received_at |
| `page_size` | `int32` | 5 |  |
| `page_token` | `string` | 6 |  |

### ListEventsResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `events` | repeated `Event` | 1 |  |
| `next_page_token` | `string` | 2 |  |

### ListIngestEndpointsRequest

No fields. The call takes its scope from the authenticated project.

### ListIngestEndpointsResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `endpoints` | repeated `IngestEndpoint` | 1 |  |

### ListSubscriptionsRequest

No fields. The call takes its scope from the authenticated project.

### ListSubscriptionsResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `subscriptions` | repeated `Subscription` | 1 |  |

### ReplayEventRequest

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `event_id` | `string` | 1 |  |

### ReplayEventResponse

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `deliveries` | repeated `Delivery` | 1 | The freshly enqueued deliveries. Replay leaves the original attempt history in place and queues new deliveries to the currently matching active subscriptions. |

### Subscription

Subscription is one project endpoint that wants events delivered.

| Field | Type | # | Notes |
| --- | --- | --- | --- |
| `id` | `string` | 1 |  |
| `endpoint_url` | `string` | 2 | HTTPS required outside loopback |
| `toolkit_slug` | `string` | 3 | empty matches all toolkits |
| `trigger_slug` | `string` | 4 | empty matches all triggers of the toolkit |
| `active` | `bool` | 5 |  |
