> Source: https://wexa.ai/docs/tools/identifiers

# Which identifier goes where

You are holding an id and you want to know which argument takes it. That is this page.

Wexa issues opaque ids and validates their format before a tool runs, so an id in the wrong
argument is refused rather than quietly ignored. Two of them are worse than that: one has to be
**split** before another tool will accept it, and one field name means two different things on the
same object.

## The short version

| The id you hold | Where you got it | What takes it |
| --- | --- | --- |
| Agent id | `create-agent` → `agent_id`; `list-agents`; the console URL | `agent_id` on `get-agent`, `update-agent`, `delete-agent`, `agent-versions`, `rollback-agent-version`; `agent_id` and `after_agent_id` on `update-process-flow`; `start_from_agent_id` on `run-agent` and `run-process-flow` |
| Agent id, **left half only** | the agent id up to the dot | `agentflow_id` on `create-schedule` |
| Process flow id | `create-process-flow` → `flow._id`; `get-process-flow` → `_id`; `flow-versions` → `process_flow_id` | `process_flow_id` on seven tools, `agentflow_id` on four — the same id under two names |
| Schedule id | `create-schedule` → `schedule_id` | `schedule_id` on `get-schedule`, `update-schedule`, `delete-schedule` |
| Execution id | `run-process-flow` — see the caveat below; the pairing is documented by the gateway, not captured here | `execution_id` on `get-execution` |
| Table id | `create-table` → `table_id`; `list-tables` → `tables[].table_id` | `table_id` on ten of the twelve Data Table tools — every one except `create-table` and `list-tables`, which do not address an existing table; `target_id` on `list-triggers` and `set-triggers` with `target_type: "table"` |
| Column id | `get-table` → `columns[].column_id` | `column_id` on `edit-column` and `delete-column`; the keys of `row` on `update-table-row` and of each `rows` entry on `insert-table-rows` |
| Row id | `query-table-rows` → `rows[]._id` — **not** `rows[].row_id` | `row_id` on `update-table-row`; `row_ids` on `delete-table-rows` |
| Skill id | `list-skills` → `skills[]` — one entry per connector action | `skill_ids` on `create-agent`; `skills` inside `agent` on `update-agent`, which is the same list under a different name |
| Model id | `list-models` → `available[].model_name` or `registry[].id` | `model` on `create-agent` and `set-model` |
| Version number | `agent-versions` / `flow-versions` → `versions[]` and `live_version`; `promote-flow` → `version` | `version` on `rollback-agent-version` and `rollback-flow-version`; `from_version` and `to_version` on `agent-versions` — all integers, not ids |
| `lifecycle_id` | every response | nothing: it is the audit handle, not an argument |

## One object, three names

A process flow is addressed by three different spellings depending on where you are looking.

- **`process_flow_id`** is the argument name on `get-process-flow`, `update-process-flow`,
  `delete-process-flow`, `run-process-flow`, `flow-versions`, `promote-flow` and
  `rollback-flow-version` — seven tools.
- **`agentflow_id`** is the argument name on `run-agent`, `run-process-flow`, `create-schedule` and
  `list-schedules` — four tools. On `run-process-flow`, which takes both, the gateway's own schema
  calls `agentflow_id` an alias for `process_flow_id`.
- **`_id`** is what the flow itself is keyed by in output: `create-process-flow` returns it as
  `flow._id`, `get-process-flow` returns it as `_id`, and `promote-flow` returns the same value as
  `agentflowId` — camel case, on that one field only.

They are one value. Nothing needs converting between them; only the name changes.

## The compound agent id, and where to split it

`create-agent` does not return a plain id. It returns two ids joined by a dot:

```json
{
  "lifecycle_id": "qlc_000105",
  "result": {
    "agent_id": "6ab17f077566f41b5c28e2ae.6ab17f074a4bd3812ca5e968"
  }
}
```

The part **before** the dot is the container the agent lives in; the part **after** it is the agent
inside that container. Every agent tool — `get-agent`, `update-agent`, `delete-agent`,
`agent-versions`, `rollback-agent-version` — takes the whole thing, dot included.

`create-schedule` does not. Its `agentflow_id` wants the container, so you pass the left half:

```json
{
  "agentflow_id": "6ab17f077566f41b5c28e2ae",
  "goal": "Summarise yesterday's orders.",
  "frequency": "0 9 * * 1"
}
```

The gateway's own schema for that argument says so — "for an agent from `list-agents`, use the part
before the dot" — and a schedule created with the left half is accepted. The two tools are addressing
different things through arguments that happen to hold ids of the same family, which is why the rule
exists at all rather than being a quirk of one tool.

## Running an agent returns three ids, and only one of them polls

`run-agent` returns a large object. Three of its fields are identifiers, and they are easy to confuse:

- **`execution_id`** — a UUID, and the **only** id `get-execution` accepts.
- **`_id`** — the run record's own key, a 24-character hex string. `get-execution` answers a 404 for it.
- **`agentflow_id`** — the flow that ran: the same id you passed in.

Verified against a live deployment. One `run-agent` call returned
`_id` `6ab192bf7566f41b5c28e2e9` and `execution_id` `3c8cf2b5-612c-4700-be57-77b4d638ef37`:

| Passed to `get-execution` | Answer |
| --- | --- |
| `_id` | `404` — "Execution flow with ID 6ab192bf7566f41b5c28e2e9 not found" |
| `execution_id` | `200`, returning the execution record |

So an agent started with `run-agent` **does** have an execution record to poll. Read `execution_id`
from the response and pass that. The argument description on `get-execution` says "Execution id
returned by `run-process-flow`", which is true but incomplete: `run-agent` returns one too.

## `row_id` means two different things

A Data Table row carries two fields whose names both suggest an identifier, and only one of them is
one.

```json
{
  "_id": "6ab179ea7566f41b5c28e260",
  "row_id": 1,
  "customer": "AcmeC",
  "amount": 120
}
```

- **`_id`** is the row's identifier: an opaque string.
- **`row_id`** is the row's position in the table: an integer, and not unique across tables.

The `row_id` **argument** on `update-table-row` and the `row_ids` argument on `delete-table-rows`
both want `_id`, despite the name. Passing the integer is refused — and the refusal reports `row_id`
as *missing* rather than as the wrong type, so read it as "not a string" when you know you sent one.

## Column ids are sometimes names

`get-table` returns a `column_id` for every column, and for the columns the platform creates itself
that id *is* the name — `_id` and `row_id` come back with `column_id: "_id"` and
`column_id: "row_id"`. Columns you add get an opaque id instead:

```json
{ "column_id": "6ab17a6b3eecba4b44e58499", "column_name": "notes", "column_type": "String" }
```

Read the id from `get-table` rather than assuming either form. When you key a `row` payload for
`update-table-row`, use `column_id`, not `column_name`.

## Ids you choose yourself

Two arguments look like ids and are not issued by the platform:

- **`session_id`** on `run-agent` and `run-process-flow` is yours to pick. Reuse the same value
  across turns to get multi-turn memory and grouping; omit it for a one-shot run.
- **`after_id`** on `list-tables` is a pagination cursor, and it has to be a `table_id` you saw on a
  previous page. A value that is not one is refused as a `ValidationError`, not as a 404.

## See also

[The tool index](/docs/tools/overview) and [errors](/docs/tools/errors).
