Every automation delivers on one channel, set by
action when it is created and fixed afterwards: SEND_EMAIL, SEND_SLACK_MESSAGE, SEND_WEBHOOK, ADD_TO_DATASET or ADD_TO_ANNOTATION_QUEUE. The channel’s configuration goes in actionParams.
Every endpoint authenticates with your project API key in the X-Auth-Token header. The same operations are in the CLI (langwatch trigger …) and the MCP server (the platform_*trigger* tools); see CLI and MCP.
Also check: Alerts and Automations for the dashboard, and Datasets from traces for the dataset column mapping.
Trace conditions: filters
filters is a JSON object whose keys are filter fields and whose values say what to match. A create with no conditions (no filters, or {}) is refused, because it would match every trace.
Most fields are unkeyed: the value is a list, and a trace matches if it has any of the listed values.
422 trigger_filter_key_required; the error message shows the nested shape to send instead.
The numeric fields (
evaluations.score, events.metrics.value) take a two-item list, [min, max]: {"evaluations.score": {"<monitorId>": ["0", "0.5"]}} matches scores from 0 to 0.5.
Evaluation keys are monitor ids
An evaluation result is recorded under the id of the monitor (the online evaluation) that produced it, so everyevaluations.* condition names a monitor id. Read them from GET /api/monitors (or langwatch monitor list): use each monitor’s id, not its evaluatorId. A condition keyed or listed by an evaluator id is refused with 422 trigger_filter_monitor_required, and the message names the monitors that run that evaluator so you can pick one.
The alternative: filterQuery
Instead of filters you can send filterQuery, a trace query in the syntax of the Trace Explorer search bar, for example status:error. When both are set, filterQuery wins. Send null on an update to clear it.
Create an automation
platformUrl that opens it in the dashboard. Optional on every kind: message, alertType (CRITICAL, WARNING or INFO), templates (Liquid templates for the Slack and email message), notificationCadence (how often a notification may send; a new automation starts on a five-minute digest) and traceDebounceMs (how long to wait for a trace to settle before its conditions are read).
What actionParams holds for each channel:
Slack delivery
ASEND_SLACK_MESSAGE automation posts through a Slack connection, named by actionParams.slackIntegrationId. Connections are added in the dashboard under Settings → Integrations → Slack, and listed there or with GET /api/slack-connections (langwatch slack-connection list on the CLI), which returns names and ids, never secrets; the API can use any connection the project can use, which is its own project connections and its organization’s organization connections.
- A bot connection also needs
slackChannelId, the channel the LangWatch Slack app posts in. - An incoming webhook connection needs no further setup: the webhook posts to the channel Slack tied it to.
slackIntegrationId and never a token or URL. A connection that is deleted, or that belongs to another project, fails delivery with slack_integration_missing.
For one release the API still accepts the legacy fields:
slackWebhook (an incoming webhook URL, with slackDelivery absent or "webhook") or slackBotToken with slackChannelId (with slackDelivery: "bot"). Send slackIntegrationId in new integrations.The server stores the secret as a connection, reusing a connection this project can already use that holds it (its own, else its organization’s) or creating a project connection, and the automation keeps only that connection’s id. An automation saved before connections existed has its stored secret moved into a connection the same way the next time it is updated.The older POST /api/trigger/slack takes exactly one destination: slack_connection_id (plus slack_channel_id for a bot connection), or slack_webhook, which is stored as a connection in the same way.Alerts on a graph
An alert watches one series of a custom graph and fires when it crosses a threshold. SendcustomGraphId, alertType and graphAlert:
filters.
Scheduled reports
A report renders something on a schedule and sends it by email or Slack. Sendreport:
Update, pause, resume and test
PATCH /api/triggers/{id}changes any field; what you leave out stays as it is.actionParamsis the exception: it replaces the delivery configuration as a whole. Credentials read back as[redacted]; send[redacted]back to keep the stored value. The channel and the kind cannot be changed.POST /api/triggers/{id}/disablepauses an automation andPOST /api/triggers/{id}/enableresumes it. A paused report stops claiming its schedule.POST /api/triggers/{id}/test-firesends the automation’s message to its saved destination, so you can check it arrives. It is not recorded as a fire. Dataset and annotation queue automations write records rather than send a message, so they cannot be test-fired.
Fire history
GET /api/triggers/{id}/fires lists what an automation has done, newest first: each fire’s id, firedAt and, for an alert, resolvedAt. It carries no trace ids and no trace content.
It pages by cursor. limit sets the page size (1 to 100, default 20). The response is { "fires": [...], "nextCursor": "..." }; send nextCursor back as cursor to read the page after this one. nextCursor is null on the last page. A cursor this endpoint did not issue is refused with a 422.
langwatch trigger fires <id> --cursor <nextCursor>, or the platform_list_trigger_fires tool with cursor.
CLI and MCP
In the CLI,
--action-params takes the channel’s configuration as JSON, and --slack-connection <id> with --slack-channel <id> (for a bot connection) are shortcuts for Slack delivery; --slack-webhook <url> is the legacy shortcut and is stored as a connection. In MCP, platform_create_trigger takes actionParams as an optional object.