---
title: "Fire a trigger"
method: POST
path: "/v1/projects/{project_id}/triggers/{trigger_id}/fire"
tags: ["Triggers"]
---

# Fire a trigger

`POST /v1/projects/{project_id}/triggers/{trigger_id}/fire`

## Request

- Base URL: `https://api.naturali.ai`
- URL: `https://api.naturali.ai/v1/projects/{project_id}/triggers/{trigger_id}/fire`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://api.naturali.ai/authorize`, token URL `https://api.naturali.ai/token`, scopes: `mcp:access`)

Fires a trigger synchronously and returns the terminal firing record. The firing itself always settles here; an `eval` target's run is queued rather than executed inline, so the record names a `queued` run to poll.

## Path parameters

- `trigger_id` string, required

## Request body

- FireTriggerRequest
  - `input` object: Fire-time input, shallow-merged over the trigger's static input. For `eval` targets it may carry `agent_version` and `baseline_run_id`.
  - `tool_context` object: Fire-time caller context, shallow-merged per key over the trigger's stored `tool_context`. A manual fire has a caller, so this is the one path that can supply a value without storing it. Forwarded exactly as written: a `{{secret:...}}` reference is resolved only in the trigger's stored bag, never in one supplied here.

## Response `200`

Terminal firing record

- TriggerFiring
  - `id` string
  - `trigger_id` string
  - `project_id` string
  - `source` 'manual' | 'webhook' | 'schedule' | 'event'
  - `status` 'queued' | 'running' | 'completed' | 'failed'
  - `input` object, nullable: Effective input, after the trigger's static input is merged under the fire-time input. For an `event` firing the fire-time input is the event envelope a webhook delivery carries (`id`, `event`, `project_id`, `resource_type`, `resource_id`, `data`, `timestamp`).
  - `result` object, nullable: { target_type, result_id, status, output } — output truncated
  - `error` StoredError: Why a resource's work failed, in the shape of an error response's `error` without `hint` and `docs_url`. Every `error` field a resource records carries it, so `code` can be read without first checking the type of `error`.
    - `code` string, required: A key from the server's ERROR_CODES registry, documented on the Error Codes page. `INTERNAL_ERROR`, with the message `Internal Server Error`, records an unexpected failure whose detail reaches the server log only.
    - `message` string, required
    - `meta` object: The failure's own structured context, when it names any.
  - `idempotency_key` string, nullable: `<event_id>:<trigger_id>` for an `event` firing, where `event_id` is the `id` in `input`; null for every other source. The same event reaching the same trigger twice produces one firing under this key, so a consumer reading firings can recognise a redelivery.
  - `attempts` integer: Dispatch attempts started. Above 1 means an earlier attempt was interrupted before it recorded a result and the firing was redelivered — not that the target refused it, which is recorded terminally in `error` and never retried.
  - `started_at` string, date-time, nullable
  - `completed_at` string, date-time, nullable
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Trigger not found
- `409`: Trigger inactive or creator unavailable

---

[API](https://skmtc.dev/naturali/apis/naturali-ai-api.md) · [All operations](https://skmtc.dev/naturali/apis/naturali-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/naturali/apis/naturali-ai-api/revisions/e4905b78f422?raw)
