---
title: "Run selected rows"
method: POST
path: "/tables/{table_id}/rows/run/"
tags: ["table-rows"]
---

# Run selected rows

`POST /tables/{table_id}/rows/run/`

## Request

- Base URL: `https://api.getoneprofile.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.getoneprofile.ai/tables/{table_id}/rows/run/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Recompute up to 1000 rows across the WHOLE dependency graph (every formula, enrichment and export column) in dependency order, as one run. This is what makes a row run correct rather than merely parallel: a column whose input another column in the same request produces waits for it, instead of reading an empty cell and skipping. `run` is null while the workflow start is still queued; the active-runs poll picks it up.

## Path parameters

- `table_id` string, uuid, required

## Request body

- TableRowsRunRequestSchema: Request body for an on-demand recompute run over rows: two scopes, one body. Send ``record_ids`` to run a checkbox selection. Send ``all: true`` to run every row the current listing matches, optionally narrowed by ``where`` / ``row_status``, exactly the predicate vocabulary of the rows query, so "run everything matching my filters" and "show me everything matching my filters" can never disagree about what matches. The explicit flag exists so an accidentally empty body runs nothing.
  - `all` boolean: Run every matching row rather than a named set. Required (and only honoured) when record_ids is absent. At most `view_scope_max_rows` rows may match; a wider listing is refused with `scope_too_large`.
  - `record_ids` string[], nullable: Record IDs of the rows to recompute.
  - `row_status` 'errored' | 'fully_computed': A row-level state, derived from its cells rather than stored. ``ERRORED`` is "any cell of this row failed to compute"; ``FULLY_COMPUTED`` is its exact complement, so the two partition the table. Serves the built-in smart views, which are questions about computation rather than about values. The ordinary filter vocabulary cannot express either.
  - `where` TableRowsWhereSchemaInput: The whole predicate for a rows query. ``items`` mixes conditions with groups under one joiner, so ``A and (B or C)`` is an AND over ``[A, group(OR, [B, C])]``. Send no ``where`` at all rather than an empty one, so "no filter" stays a single state. The cap is on LEAVES, not on items: eight conditions cost eight correlated EXISTS clauses whether they are grouped or not, and it is the clause count that the query planner pays for.
    - `items` TableRowWhereItemSchemaInput[], required: Conditions and groups.
      - union
        - TableRowFilterSchemaInput: One predicate a row must satisfy. Which operators apply depends on the column's type: a range comparison on a checkbox is rejected rather than silently matching nothing. The valueless operators (``is_empty``, ``is_not_empty``, ``is_true``, ``is_false``) must not carry a value.
          - `column_id` union, required: A column ID, or `__any_column__` to ask about every cell in the row at once. `__any_column__` takes only `has_error` and `has_no_error`.
            - string, uuid
            - '__any_column__' | '__record_id__': The filter targets that name the whole ROW rather than one column. ``ANY_COLUMN`` asks a question of every cell in the row at once: "does any column have an error?" is the table-wide half of the per-column ``has_error``. It stands in the ``column_id`` slot of an ordinary condition (the same trick the system sort keys use), so a row-wide question travels through every surface that already carries a predicate tree (a saved view, a run's scope, an export, a count) with nothing to add to any of them. The dunder spelling keeps it apart from any UUID.
          - `operator` 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'contains_any_of' | 'not_contains_any_of' | 'starts_with' | 'is_true' | 'is_false' | 'is_empty' | 'is_not_empty' | 'has_error' | 'has_no_error' | 'has_results' | 'has_no_results' | 'has_not_run' | 'is_stale' | 'is_not_stale' | 'run_condition_not_met' | 'run_stopped', required: A row filter predicate. Which operators are legal depends on the column's data type; the service validates the pairing and rejects a mismatch, so an operator here is a vocabulary entry rather than a promise it applies everywhere. Two families live here. The VALUE operators ask about what a cell holds and are keyed off the column's storage slot. The STATE operators ask about what the last run DID to the cell (errored, skipped, never ran, went stale) and are keyed off the column's kind instead: they read the compute metadata that only a computed column ever writes, and mean nothing on a hand-typed one.
          - `type` 'condition'
          - `value` union
            - string
            - integer
            - number
            - boolean
            - string, date-time
            - string, date
            - CellValueInput[]
            - object
        - TableRowFilterGroupSchemaInput: A parenthesised run of conditions, joined among themselves. Holds conditions and never groups: one level of nesting is expressible and a second is not, structurally. That covers ``A and (B or C)`` (what a filter panel offers) while keeping the SQL a flat walk.
          - `conditions` TableRowFilterSchemaInput[], required: The conditions inside the parentheses.
            - `column_id` union, required: A column ID, or `__any_column__` to ask about every cell in the row at once. `__any_column__` takes only `has_error` and `has_no_error`.
              - …
            - `operator` 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'contains' | 'not_contains' | 'contains_any_of' | 'not_contains_any_of' | 'starts_with' | 'is_true' | 'is_false' | 'is_empty' | 'is_not_empty' | 'has_error' | 'has_no_error' | 'has_results' | 'has_no_results' | 'has_not_run' | 'is_stale' | 'is_not_stale' | 'run_condition_not_met' | 'run_stopped', required: A row filter predicate. Which operators are legal depends on the column's data type; the service validates the pairing and rejects a mismatch, so an operator here is a vocabulary entry rather than a promise it applies everywhere. Two families live here. The VALUE operators ask about what a cell holds and are keyed off the column's storage slot. The STATE operators ask about what the last run DID to the cell (errored, skipped, never ran, went stale) and are keyed off the column's kind instead: they read the compute metadata that only a computed column ever writes, and mean nothing on a hand-typed one.
            - `type` 'condition'
            - `value` union
              - …
          - `joiner` 'and' | 'or': How the members of one filter level combine.
          - `type` 'group'
    - `joiner` 'and' | 'or': How the members of one filter level combine.

## Response `201`

Successful Response

- TableRowsRunResponseSchema: Result of requesting a row-scoped recompute run. ``run`` is None while the workflow start is still queued. The run row is minted post-commit, and the active-runs poll picks it up.
  - `request_id` string, uuid, nullable: The id of this run request. The run is minted with it as its origin, so it is known at once, even while `run` is still null.
  - `run` TableRunReadSchema, required: A table recompute run with its static denominator and monotone counters.
    - `cells_awaiting` integer, required: Cells the run held because an input they read has not been computed yet. Not a final state: a later run fills them. Counted within cells_done.
    - `cells_done` integer, required: Cells processed so far; clamped to cells_total so the banner can never overshoot.
    - `cells_failed` integer, required: Cells whose formula evaluation failed.
    - `cells_no_data` integer, required: Cells that ran clean but found nothing. Never retried, and excluded from errored views. Free for a lookup; an AI column's cell is charged what it used. Counted within cells_done.
    - `cells_skipped` integer, required: Cells the run deliberately skipped: a missing required input or a false run condition. Counted within cells_done.
    - `cells_total` integer, required: Exact static denominator, fixed when the run plan is minted.
    - `column_id` string, uuid, nullable: The column a column-lineage run recomputes, parsed from its workflow identity; null for whole-table runs. Narrows the grid's busy paint to one column; `row_scope` is what narrows it to the rows within that column.
    - `column_ids` string[], nullable: Every column this run's plan covers, in dependency (layer) order, not the order they were requested in. Null on runs minted before the plan was published, where column_id is all there is. This is what narrows the grid's busy paint when one run covers several columns, which column_id cannot express.
    - `completed_at` string, date-time, nullable, required
    - `created_at` string, date-time, required
    - `credits_charged` number: Credits charged so far. Grows while the run works, as its finished cells are settled every few seconds; final once the run ends.
    - `error` string, nullable, required: Failure description when the run status is failed.
    - `export_retry_attempt` integer: How many automatic export retries preceded this run. 0 is a run a person or a schedule asked for; higher values mark the follow-ups queued for rows whose push failed for a retryable reason, so a run history can tell 'we tried again' from 'you ran it again'.
    - `id` string, uuid, required
    - `row_scope` TableRunRowScopeReadSchema, required: The rows a run resolved to: what lets a client mark exactly those busy. ``record_ids`` is populated for the ``record_ids`` kind alone. ``all_rows`` and ``unlisted`` both mean "assume every row": the first because it is true, the second because the set was too large to carry on every frame. Collapsing them keeps a client's fallback one branch rather than two.
      - `kind` 'all_rows' | 'record_ids' | 'unlisted', required: How a minted run's RESOLVED row set is published to readers. Distinct from :class:`TableRunScope`, which is what the caller ASKED for. The two disagree routinely (``ALL`` on a ``keep_existing_results`` table is silently narrowed to the unfilled rows at mint) and only the resolved set can be painted, so only the resolved set is stored. ``UNLISTED`` is a real row subset whose ids were too many to carry on every changefeed frame (see ``max_persisted_scope_rows``). It reads exactly like ``ALL_ROWS`` to a client: assume every row. That keeps the fallback one branch rather than two, at the cost of over-painting the rare huge partial.
      - `record_ids` string[], nullable, required: The exact rows the run will touch; null unless kind is record_ids.
      - `rows` integer, nullable, required: Rows the resolved scope covers; null for all rows.
    - `started_at` string, date-time, nullable, required
    - `status` 'pending' | 'running' | 'cancelling' | 'cancelled' | 'paused_for_credits' | 'completed' | 'completed_with_errors' | 'failed', required: Lifecycle status of a table run. ``PENDING`` exists for API compatibility but is never observed: runs are born ``RUNNING`` at mint. ``CANCELLING`` is the requested-stop state the page activities observe; the workflow finalizes it to ``CANCELLED``.
    - `table_id` string, uuid, required
    - `trigger` 'cell_edited' | 'row_added' | 'row_manual' | 'column_added' | 'column_edited' | 'column_manual', required: What kind of mutation requested a recompute run.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Table not found
- `422`: Invalid request made to the API.
- `500`: Internal server error.
- `502`: Bad gateway error.
- `503`: Service unavailable.

---

[API](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile.md) · [All operations](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/llms.txt) · [OpenAPI document](https://skmtc.dev/getoneprofile/apis/api-reference-oneprofile/revisions/4a6bd71e3f02?raw)
