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

# Triggers

> The immutable audit anchor for every run — its type/source split, the read-only /triggers surface, and admin-only raw_request

A **trigger** is the immutable audit record of *what caused a run*. Every time a definition runs — whether you called the API, a webhook delivery arrived, a schedule fired, or an internal event matched — GetDialed writes exactly one trigger, then produces a [batch](/concepts/batches-and-executions) and its executions from it.

Triggers are **write-once**: they are never updated or deleted. A trigger that failed to spawn a batch is still a valid audit record — the anchor exists so you can always answer "where did this run come from?" long after the run itself has aged out.

```json theme={null}
{
  "id": "trigger_44556677",
  "org_id": "org_a1b2c3d4",
  "definition_id": "def_a1b2c3d4",
  "type": "webhook",
  "source": "salesforce",
  "created_at": "2026-07-09T17:59:59Z"
}
```

## Type vs. source

A trigger carries two independent dimensions. They are **not** the same field, and they filter separately:

| Dimension  | Field    | Set by                                          | Values                                                                                |
| ---------- | -------- | ----------------------------------------------- | ------------------------------------------------------------------------------------- |
| **Type**   | `type`   | The platform, deterministically per entry point | `api_call`, `webhook`, `schedule`, `event`                                            |
| **Source** | `source` | The caller, optionally                          | Free-form label (e.g. `salesforce`, `ui`, `csv_upload`) — or `null` when not supplied |

**Type** answers *which entry point created this run* and is always populated. **Source** answers *which upstream system or workflow the caller attributed it to* and is nullable — the platform never infers it. A nightly cron and a manual UI click can both carry `source: "ui"` while differing in `type`; a webhook and an API call can share `type` semantics while differing in `source`.

<Note>
  The `type` and `source` values are denormalized onto every [batch](/concepts/batches-and-executions) (`trigger_type`, `trigger_source`) and execution, so a runs feed can filter or group by either dimension without a second lookup against the trigger.
</Note>

## The read-only surface

Triggers are created only as a side effect of a run — there is **no** `POST`, `PUT`, or `PATCH`. The `/triggers` surface is read-only:

| Method | Endpoint                         | Purpose                                                                                                                                                                  |
| ------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET`  | `/triggers`                      | List your org's triggers, newest first. Filter by `type`, `source`, and a `created_at` date range (`since` / `until`). Converged `Page` envelope with cursor pagination. |
| `GET`  | `/triggers/{trigger_id}`         | Fetch one trigger's detail.                                                                                                                                              |
| `GET`  | `/triggers/{trigger_id}/batches` | The audit drilldown — every batch this trigger produced. Converged `Page` envelope.                                                                                      |

Every route is tenant-scoped: a missing or cross-tenant trigger returns `404` (never `403`). The nested `/batches` route verifies you own the parent trigger before listing its children.

<Note>
  Today a trigger maps to exactly one batch (1:1). The nested `GET /triggers/{id}/batches` route is shaped as a list so it stays forward-compatible with future record-partitioning, where one trigger may fan out into several batches.
</Note>

## `raw_request` is admin-only and detail-only

Every trigger stores the **raw inbound payload** that caused it — the webhook body, the event envelope, or the API trigger request. This blob can hold PII, HMAC signatures, and arbitrary caller data, so it is doubly gated:

* **Detail-only.** `raw_request` is returned **only** on `GET /triggers/{trigger_id}`. It is **omitted entirely** from every list response — it never appears in `GET /triggers` or `GET /triggers/{id}/batches` items.
* **Admin-only.** Even on the detail route, `raw_request` is included **only** for an admin principal (an `X-API-Key` is admin-equivalent, or a Clerk JWT with the admin role). Non-admin callers get the trigger's `type`, `source`, timestamps, and back-references — but not the raw blob.

<Warning>
  `raw_request` is the audit-forensics escape hatch. Its blast radius is deliberately minimized: it is the single field on the entire read surface that is both admin-gated **and** detail-only. Non-admin principals and every list view never see it.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Batches and executions" icon="list-check" href="/concepts/batches-and-executions">
    How a trigger becomes a batch and its executions.
  </Card>

  <Card title="How GetDialed works" icon="diagram-project" href="/concepts/architecture">
    The core objects — definitions, triggers, batches, and executions.
  </Card>
</CardGroup>
