---
title: "Estimate the credit cost of a column run"
method: POST
path: "/tables/{table_id}/columns/{column_id}/run/estimate/"
tags: ["table-columns"]
---

# Estimate the credit cost of a column run

`POST /tables/{table_id}/columns/{column_id}/run/estimate/`

## 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}/columns/{column_id}/run/estimate/`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Estimate the credit cost of an on-demand column run without running it. Takes the same request body as the run endpoint so estimate and run can never disagree about scope. Free runs (formula/manual columns) estimate to zero and are always sufficient.

## Path parameters

- `table_id` string, uuid, required
- `column_id` string, uuid, required

## Request body

- TableColumnRunRequestSchema: Scope for an on-demand recompute of one formula column.
  - `limit` integer, nullable: Row count for scope=first_n (default 10).
  - `offset` integer, nullable: Starting-row offset in display order for scope=first_n; omit to start at the first row.
  - `record_id` string, uuid, nullable: The target row for scope=cell; see also record_ids.
  - `record_ids` string[], nullable: The target rows for scope=cell: a swept selection re-runs in one request rather than one per cell. Wins over record_id when both are sent; scope=cell requires at least one of the two.
  - `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.
  - `scope` 'all' | 'errored' | 'unfilled' | 'first_n' | 'cell', required: Row scope for an on-demand ``COLUMN_MANUAL`` run. ``CELL`` (a single row, origin-keyed so independent cell re-runs never terminate each other) rides the same enum as the column-lineage scopes. ``UNFILLED`` is "empty or out-of-date": errored, stale, valueless and never-computed cells, minus fresh deliberate skips, which would only skip again.
  - `sorts` TableRowSortSchema[], nullable: The grid's active sort, so `first_n` means the first N rows the person can SEE rather than the first N in stored order. Ignored by every other scope.
    - `column_id` union, required: A column ID, or `__created_at__` / `__updated_at__` to order by when the row was added or last edited.
      - string, uuid
      - '__created_at__' | '__updated_at__': The sort keys that order by the ROW rather than by one column's cells. ``CREATED_AT`` is when the row was added; ``UPDATED_AT`` is when any of its cells last changed (the row was added, for one with no cells). They share the sort slot with column IDs, so a query or a saved view names either the same way; the dunder spelling keeps them apart from any UUID.
    - `direction` 'asc' | 'desc': Which way a sorted row listing runs.
  - `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 `200`

Successful Response

- TableColumnRunEstimateResponseSchema: Estimated credit cost of an on-demand column run, before running it. Free runs (formula/manual columns) estimate to zero and are always sufficient, even at a zero balance. The figure is an estimate: row counts and cell freshness can shift between estimating and running.
  - `balance_sufficient` boolean, required: Whether the organization's available credits cover the estimate.
  - `cells_total` integer, required: All cells the run would compute, charged or not.
  - `columns` ColumnRunEstimateSchema[]: Every enrichment or export column the run would work on, in the order it runs: the column asked for first, then the columns that read it. Each with the most its part can cost and what it usually costs.
    - `column_id` string, uuid, required
    - `credits_at_most` number, required: The most this column's part of the run can cost, in credits.
    - `credits_usually` number, required: What this column's part usually costs, in credits, from what the same kind of cell has been charged before, or a typical share of credits_at_most while there is no history yet. Equal to credits_at_most for a flat price.
    - `display_name` string, required: The column's name, as the table shows it.
  - `estimated_credits` number, required: The most the run can cost, in credits: every row of every paid column charged its full per-row price. What the credit hold and the confirmation gate reason about.
  - `expected_credits` number: What a run like this usually costs, in credits: a column charged by use (an AI column) at the share of its per-row maximum the same kind of cell has actually been charged (a typical share while there is no history yet), every other column at its price. Quote both: up to estimated_credits, usually about expected_credits. Equal to estimated_credits for a flat price (no column charged by use, as in a run of enrichments): then quote that one figure, without up to.
  - `export_writes` ExportWriteEstimateSchema[]: Export columns this run would fire. Present so the confirmation can name the destination, the object and the action instead of only a row count. Empty for a run that writes nothing outside this table.
    - `action` string, required: create, update or upsert: what happens to records that already exist at the destination.
    - `column_id` string, uuid, required
    - `display_name` string, required: The export column's name, for the confirmation copy.
    - `integration_type` string, required: Destination provider slug, e.g. 'hubspot'.
    - `record_type` string, required: Destination object written, e.g. 'contacts'.
    - `rows` integer, required: Rows this column would attempt to write.
  - `is_estimate` boolean, required: Always true: freshness and row counts can shift by run time.
  - `requires_confirmation` boolean: True when the estimate crosses the confirmation threshold: ask before spending instead of running on first click.
  - `rows_held_back` integer: Rows in scope the column's run condition would hold back. Already subtracted from rows_in_scope.
  - `rows_in_scope` integer: Rows the run would cover. This is what a scope choice is about, and what the credit estimate is derived from; `cells_total` also counts the dependent columns the run would recompute.
  - `scope_too_large` boolean: True when the filtered view names more rows than a run may be scoped to (`view_scope_max_rows`). `rows_in_scope` still carries the matching count; the run itself would be refused with `scope_too_large`. Narrow the filter, or run the whole table.
  - `unit_price` number, required: Blended credits per charged cell (total estimate / units); 0 for free runs.
  - `units` integer, required: Cells that would incur a charge (0 for free runs).

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Table column 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)
