---
title: "Make a trigger: which events fire it, a filter, where the event goes"
method: POST
path: "/api/v1/triggers"
tags: ["Triggers"]
---

# Make a trigger: which events fire it, a filter, where the event goes

`POST /api/v1/triggers`

## Request

- Base URL: `https://api.roma.app`
- URL: `https://api.roma.app/api/v1/triggers`
- Auth: HTTP bearer

The user's triggers — Roma delivering an event to an outside agent the moment something changes on their lists — in one tool: `action` list, create, update or delete. A trigger names which events fire it, a filter, and where the event goes: transport `webhook` POSTs a signed envelope ({ eventId, name, timestamp, text, data, cursor }; Standard Webhooks headers webhook-id, webhook-timestamp, webhook-signature over `id.timestamp.body` with the secret) to `url`, which must be https and public (no challenge: a Claude scheduled task's Fire URL with its bearer in `headers` works as is), the secret answered once on create; transport `poll` needs no address: the agent reads its deliveries at GET /api/v1/triggers/{id}/deliveries?wait=25&after=<cursor> with its key. `data` carries the item as get_item returns it, `changes` with from and to per field, and the actor. Retries at 1 minute, 1 hour and 6 hours, then the trigger is disabled as failing; `update` with `paused: false` or a new `url` brings it back. Pass `agentName`, the name you post under with post_chat_message: the person's reply to one of your posts then fires the trigger too, and the chat offers them Reply. The transport never changes on update: delete and create again. Twenty per account. `list` answers the triggers with each one's last delivery and the catalogue of events: item.created (an item was created on one of the person's lists: a task, a note, a row); item.updated (an item's title, due date, reminder, a property value or its archived flag changed); item.statusUpdated (a task's status changed (todo, inprogress, completed)); item.moved (an item moved onto another list); item.deleted (an item was deleted into the trash (recoverable for 30 days)); item.restored (an item came back from the trash); list.created (a list was created); list.updated (a list's name, icon, instructions, properties or archived flag changed); list.deleted (a list was deleted into the trash); list.restored (a list came back from the trash); item.assigned (the person assigned an item to an agent: a person property of the item gained the agent's record (`data); message.posted (the person replied to an agent's post in an item's chat (reply on its row; `data); automation.completed (an automation's run finished (`data).

## Request body

- object
  - `triggerId` string: For update and delete: the trigger's id (from list).
  - `name` string: For create (required) or update: what it wakes: "Claude Code on the Mac", "Codex for testing".
  - `events` string[]: For create (required) or update: which events fire it.
  - `filter` object, nullable: What narrows an event to this trigger. Every part optional; an absent part matches everything.
    - `listIds` string[]: Only events about items on these lists (any of).
    - `fields` string[]: For item.updated, item.statusUpdated and item.moved: only when one of these fields changed: title, status, dueAt, archived, listId, or a property's name.
    - `equals` object: Only when every named field has this value on the item after the change: { "status": "inProgress" }, { "Stage": "ready to go" }. A property by its name; an option by its label.
    - `agentName` string: For message.posted: only the person's replies addressed to this agent name, never the agent's own posts.
  - `transport` 'webhook' | 'poll': For create: webhook (default, needs url) or poll (no address; read with the deliveries route).
  - `url` string, uri: For a webhook: the https address Roma POSTs to (create), or the new one (update).
  - `secret` string: For a webhook on create: your own whsec_ secret (base64, 32 bytes); minted when absent.
  - `headers` object: For a webhook: extra request headers on every POST, e.g. { "Authorization": "Bearer …" } for a Claude Routine fire URL. Stored, never read back; on update they replace the old ones.
  - `agentName` string: The agent this trigger wakes, exactly as you name yourself in post_chat_message ("Claude Code"). The person's replies to your posts fire this trigger too. On update, empty clears it.
  - `agentId` string: The agent RECORD this trigger wakes (one of the person's agents, register_agent): its assignments (item.assigned) and the replies to its posts fire it. On update, empty clears it.
  - `paused` boolean: For update: true pauses, false resumes.

## Response `201`

Created; the body is the new item.

- object
  - `triggers` object[]: For list.
    - `id` string, required
    - `name` string, required
    - `transport` 'webhook' | 'poll' | 'mcpEvents' | 'email', required
    - `events` string[], required
    - `filter` unknown, required
    - `url` string, nullable, required
    - `disabledAt` string, nullable, required
    - `disabledReason` string, nullable, required
    - `lastDeliveryAt` string, nullable, required
    - `lastDeliveryStatus` string, nullable, required
    - `createdAt` string, required
    - `lastDelivery` unknown, required
  - `events` object[]: For list: the catalogue.
    - `name` string, required
    - `description` string, required
  - `trigger` object: For create and update.
    - `id` string, required
    - `name` string, required
    - `transport` 'webhook' | 'poll' | 'mcpEvents' | 'email', required
    - `events` string[], required
    - `filter` unknown, required
    - `url` string, nullable, required
    - `disabledAt` string, nullable, required
    - `disabledReason` string, nullable, required
    - `lastDeliveryAt` string, nullable, required
    - `lastDeliveryStatus` string, nullable, required
    - `createdAt` string, required
    - `paused` boolean
  - `secret` string, nullable: For create: the signing secret, this once; null for a poll trigger.
  - `deleted` boolean: For delete.

## Other responses

- `400`: The request was understood and refused; the error says what to change.
- `401`: No usable bearer token.
- `404`: No such item for this account.
- `405`: The path exists but not with this method; Allow lists the ones that work.
- `429`: Over the rate limit; wait for Retry-After.

---

[API](https://skmtc.dev/roma/apis/roma-api.md) - [All operations](https://skmtc.dev/roma/apis/roma-api/llms.txt) - [OpenAPI document](https://skmtc.dev/roma/apis/roma-api/revisions/3dd91459b0fb?raw)
