---
title: "Retrieve an automation run"
method: GET
path: "/companies/{company}/automations/runs/{run}"
tags: ["Automations"]
---

# Retrieve an automation run

`GET /companies/{company}/automations/runs/{run}`

## Request

- Base URL: `https://api.factuarea.com/v1`
- URL: `https://api.factuarea.com/v1/companies/{company}/automations/runs/{run}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Retrieve one run with its frozen definition version, the triggering event `data.object` and its steps in order.
- The snapshots keep old runs readable after the rule changes.
- A run of another company returns 404 `automation_run_not_found`.

## Path parameters

- `company` string, uuid, required
- `run` string, uuid, required

## Headers

- `Factuarea-Version` string, date

## Response `200`

- object
  - `data` AutomationRun, required: One execution of an automation rule, with its steps. Delivered as the `data.object` of the `automation_run.*` webhook events, captured at emission time and frozen there: a run snapshotted while `running` keeps showing `running` even after it completes. It carries the frozen definition it executed (`rule_version` + `rule_snapshot`) and the frozen payload of the event that triggered it (`event_payload`), so an execution stays readable weeks later, when the rule has moved on to a newer version.
    - `id` string, uuid, required: Opaque identifier of the run, a UUID v7 (e.g. `01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a9b`).
    - `object` 'automation_run', required: Always `automation_run`.
    - `automation_rule_id` string, uuid, required: UUID v7 of the automation rule that produced this run.
    - `rule_version` integer, required: Version number of the rule definition this run executed. It can lag behind the rule’s `current_version`: editing a rule never rewrites past runs.
    - `rule_snapshot` object, required: The rule definition of `rule_version`, frozen at execution time (its condition tree and its actions with their parameters). Returned verbatim, because its shape is defined by the account owner.
    - `trigger_type` string, required: Event the rule listens to, in `resource.action` form. It is the trigger of the rule, not necessarily identical to `event_name` in future versions of the matcher.
    - `subject_company` object, nullable, required: The tax ID this run acted upon, when it comes from a rule of scope `cartera`. It is `null` for runs of scope `empresa`, which act on the company that owns the rule and have no subject. `id` and `name` are themselves `null` when the company cannot be read at that moment: the block is still emitted, so a portfolio run stays distinguishable from a company-scoped one. When the tax ID is deleted, the run is kept but its link to the company is cleared, so `subject_company` becomes `null`, as in a run of scope `empresa`.
      - `id` string, uuid, nullable, required: Opaque identifier of the tax ID, a UUID v7, or `null` when it can no longer be read.
      - `name` string, nullable, required: Name of the tax ID, or `null` when it can no longer be read.
    - `event_name` string, required: Public name of the event that triggered this run (e.g. `invoice.paid`), one of the types returned by `GET /v1/event-catalog`.
    - `event_aggregate_id` string, uuid, required: UUID v7 of the resource the triggering event happened on (the invoice that was paid, the quote that was accepted, …).
    - `event_occurred_on` string, date-time, nullable, required: When the triggering event happened (ISO 8601), or `null` when the emitter did not record it.
    - `event_payload` object, required: The `data.object` of the triggering event, frozen at execution time. Its keys are those of the resource of `event_name`, so the shape varies with the trigger and it is returned verbatim.
    - `correlation_id` string, nullable, required: Identifier shared by everything that descends from the same originating event, so a chain of automations can be followed end to end. `null` when the emitter did not propagate one.
    - `chain_depth` integer, required: How deep this run sits in a chain of automations triggering one another (`0` for a run triggered directly by a business event). The platform caps the depth to stop runaway chains: a run over the cap is blocked with reason `chain_depth_exceeded`.
    - `status` 'pending' | 'running' | 'completed' | 'failed' | 'dead_lettered' | 'blocked', required: State of the run: `pending` (queued), `running`, `completed`, `failed` (finished without producing its effect and not reprocessable), `dead_lettered` (parked awaiting a manual replay) or `blocked` (stopped by a guardrail such as the chain-depth cap, the rate limit or the monthly budget).
    - `attempts` integer, required: Attempts the run has consumed.
    - `discard_reason` string, nullable, required: Classified reason why the run did not produce its effect, or `null` while it has not finished in the red. It is what tells apart a run stopped by a guardrail (`chain_depth_exceeded`, `rate_limit_exceeded`, `monthly_budget_exhausted`) from one that exhausted its attempts (`step_attempts_exhausted`) or timed out (`run_execution_timeout`) — a guardrail cut-off has no step carrying a reason, so this is the only place it shows. Returned VERBATIM as stored: the current engine writes values of a closed catalogue, but rows written before that catalogue existed still hold free-form text, so do not model this as a fixed enum.
    - `discard_reason_label` string, nullable, required: Human-readable label of `discard_reason`, in Spanish. `null` when there is no reason, or when the stored value predates the closed catalogue and therefore cannot be interpreted — in that case `discard_reason` still carries the raw value. The label is always Spanish: it is part of the vocabulary of the automation engine and does not follow `Accept-Language`.
    - `last_error` string, nullable, required: Technical message of the last failure, or `null`. Free-form text meant for debugging: the classified reason of the outcome is `discard_reason` (and the `discard_reason` of each step), an orthogonal axis.
    - `started_at` string, date-time, nullable, required: When the run started (ISO 8601), or `null` while it is still queued.
    - `finished_at` string, date-time, nullable, required: When the run reached its outcome (ISO 8601), or `null` while it has not finished.
    - `created_at` string, date-time, nullable, required: When the run row was created (ISO 8601).
    - `updated_at` string, date-time, nullable, required: When the run row was last modified (ISO 8601).
    - `steps` object[], required: Steps of the run, ALWAYS in execution order — the order is part of the contract, because `step_index` is the identity of a step. The `automation_run.step_dead_lettered` event publishes the index of the parked step as the extra key `data.step_index`: resolve it here, against the element whose `step_index` matches.
      - `id` string, uuid, required: Opaque identifier of the step, a UUID v7.
      - `object` 'automation_step_run', required: Always `automation_step_run`.
      - `step_index` integer, required: Zero-based position of the step inside its run, unique within the run. It is the identity of the step: it is what `automation_run.step_dead_lettered` publishes as `data.step_index`, and what `POST /v1/companies/{company}/automations/runs/{run}/steps/{step_index}/replay` takes.
      - `action_type` 'notify_in_app' | 'notify_channel' | 'emit_webhook' | 'create_calendar_event' | 'send_document_email' | 'send_payment_reminder' | 'change_status' | 'tag_entity' | 'create_task' | 'change_task_status' | 'assign_task' | 'add_task_comment', required: Type of action of the step, as frozen in the rule version snapshot.
      - `status` 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped' | 'dead_lettered' | 'blocked', required: State of the step: `pending`, `running`, `succeeded`, `failed`, `skipped`, `dead_lettered` (parked awaiting a manual replay) or `blocked` (stopped by a guardrail).
      - `attempts` integer, required: Attempts the step has consumed.
      - `parameters` object, required: Parameters of the action, frozen from the rule version snapshot. `{}` when the action takes none.
      - `result` object, required: Trace the action adapter returned. `{}` while the step has not finished, or when the adapter produced no trace.
      - `discard_reason` string, nullable, required: Classified reason of the step outcome, or `null` when there is none. Returned VERBATIM as stored: the current engine writes values of a closed catalogue (`condition_not_matched`, `chain_depth_exceeded`, `step_attempts_exhausted`, …), but rows written before that catalogue existed still hold free-form text, so do not model this as a fixed enum. The catalogue value IS guaranteed on the `data.discard_reason` extra of `automation_run.step_dead_lettered`.
      - `discard_reason_label` string, nullable, required: Human-readable label of `discard_reason`, in Spanish. `null` when there is no reason, or when the stored value predates the closed catalogue and therefore cannot be interpreted — in that case `discard_reason` still carries the raw value. The label is always Spanish: it is part of the vocabulary of the automation engine and does not follow `Accept-Language`.
      - `replayable` boolean, required: Whether replaying this step can produce a different outcome. `true` only for reasons caused by an external state you can change (a disconnected channel, a client without an e-mail address, exhausted attempts): those park the step in `dead_lettered`, the only state that allows re-entry. `false` for reasons frozen into the rule snapshot (an unregistered action type, invalid parameters) and for guardrail cut-offs, where a replay would take exactly the same branch. Also `false` when the reason is unknown to the catalogue.
      - `last_error` string, nullable, required: Technical message of the last failure of the step, or `null`. Orthogonal axis to `discard_reason`: this one is the raw message, that one is the classification.
      - `next_retry_at` string, date-time, nullable, required: When the step is scheduled to be retried (ISO 8601), or `null` when no retry is pending.
      - `claimed_at` string, date-time, nullable, required: When a worker claimed the step (ISO 8601), or `null` while unclaimed.
      - `finished_at` string, date-time, nullable, required: When the step reached its outcome (ISO 8601), or `null` while it has not finished.

## Other responses

- `400`: `parameter_unknown` with `subcode` `retired_active_profile_header`: the retired `X-Active-Profile` header was sent; the company goes in the path. `parameter_invalid_format` on `Factuarea-Version`: the header is not a `YYYY-MM-DD` date. `unsupported_api_version`: the `Factuarea-Version` date is not a supported version.
- `401`: Missing or invalid API key.
- `403`: The request is authenticated but not allowed: the API key lacks the required scope (`insufficient_scope`), the plan does not include the public API or this feature (`addon_not_active`, `feature_not_available_in_plan`), or the module is not available with a test key (`module_not_available_in_sandbox`). `company_inactive`: the company in the path is deactivated; reactivate it to operate.
- `404`: The requested resource does not exist or belongs to another company. `profile_not_found`: the company in the path does not exist, is not in the API key scope or belongs to the other environment (live or test).
- `429`: Rate limit exceeded. Retry after the duration in `Retry-After`.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/factuarea/apis/factuarea-public-api.md) · [All operations](https://skmtc.dev/factuarea/apis/factuarea-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/factuarea/apis/factuarea-public-api/revisions/718e77934422?raw)
