List counterparties
well_list_counterpartiesList the workspace's counterparty companies and how each one is CATEGORIZED — the company-level industry labels a counterparty carries. Use it for "which suppliers have no category?", "what industries are my counterparties in?", and before categorizing a counterparty so you name real ids instead of guessing.
Name a scope, and say whether to keep only the ones missing a category:
periods: [{ calendar_year, calendar_month }, …](1-12): the counterparties whose invoices those months are still missing, categorized ones included, each row tagged with its month and carryingtx_count,base_total_amountinbase_currency, andsuggested_retrieval. Every month must have ended.periodsPLUSuncategorized_only: true: the same months, keeping ONLY the counterparties that carry no category. Use this whenever the question is which of a period's suppliers still need one, and whenever a step asks the user to categorize them: the categorized ones are not the work, and listing them buries it.uncategorized_only: truealone: a WORKSPACE-WIDE sweep for every counterparty that carries no category, no month involved. Returns 50 rows per page plustotal_count;tx_count,base_total_amountandsuggested_retrievalare null because the call names no period. Whennext_cursoris not null the sweep has more counterparties: call again withcursorset to it to read them. It is a POSITION, not a row offset, so categorizing the rows of one page never hides the rows of the next. Only this sweep pages:cursoris refused besideperiods.missing_ledger_only: truealone: the LEDGER-ASSIGNMENT worklist — the counterparties that have a bank transaction and still need a ledger account (COA) default set for the direction their transactions take. Its rows ride inledger_rows, notrows, each carryingneeds_payable/needs_receivableand the AP/AR default it holds now; a needed slot is empty, assigned from the chart of accounts. This is a DIFFERENT question from categorization: it assigns a ledger account, not an industry label. Set a default withwell_update_company({ account_payable_default_id | account_receivable_default_id }); read the account ids withwell_list_ledger_accounts. It returns the first 500 counterparties needing a default, so a worklist that fills 500 (total_countequal torow_countat 500) is a FLOOR: assign those and read the scope again for the rest. It is its own scope — never combine it withperiods,uncategorized_only, orcursor.
COST: the period form has no batch endpoint, so each named month is a separate read of that month's spend. Ask for the months the user actually named, not a whole year "to be safe".
Every row carries categories ([{ category_id, name }]) and is_categorized. categorized_count and uncategorized_count count the COUNTERPARTIES OF THE SCOPE, once each however many months they appear in, not the rows returned. Under uncategorized_only the result lists the uncategorized ones alone while categorized_count still counts the ones it withheld, so the two together are the period's coverage and uncategorized_count is the work left. Report both: naming the listed rows as the period's whole counterparty set overstates how much is uncategorized.
TO SET a counterparty's categories, call well_update_company({ company_id, category_ids: [...] }) — that field REPLACES the company's whole set. Read the available labels first with well_query_records({ root: "categories", whereClause: { category_type: { _eq: "company" } } }): that is the company-category catalog. It has no curated allowlist — the labels are minted during enrichment — so pass ids from it rather than inventing a taxonomy.
suggested_retrieval is derived from the PROVIDER match, not from the category. Categorizing a counterparty does not change it; do not tell the user otherwise.
This tool only reads. It categorizes nothing, mints no task, connects nothing and fetches no invoice.
No workspace read is needed first: the workspace is resolved from the caller's authorized token, same as every other well_* tool.
When the user asks to see, list or fix these rows, call this tool directly: its card is the answer. ⚠️ This tool draws its card on EVERY call, the empty one included. So when nobody asked for the list and you only need to CHECK whether anything is left (the first pass of a gate, or a re-check after a repair), call well_get_worklist_status({ worklist: "counterparties_to_categorize", periods }) first, with the same scope you would pass here. It draws nothing. Call this tool after it only when it answers open: true.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | The next page of the workspace-wide uncategorized sweep: pass back the `next_cursor` the previous call returned. Only that sweep pages, so this needs `uncategorized_only: true` and NO `periods`, because a period scope returns every month it covers in one call. | |
| periods | No | The calendar months whose counterparties to list, 1-12. Each month costs one separate read of that month's spend. Duplicates are refused. | |
| workspace_id | No | Target workspace. This read reports one workspace's own data. Omit it and the token's primary workspace answers, which may not be the one you mean; the result names the workspace that did. | |
| conversation_id | No | The conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation. | |
| uncategorized_only | No | Keep only the counterparties that carry no industry category. WITH `periods`: the uncategorized counterparties OF those months. Use it whenever the question is which of a period's suppliers still need a category. WITHOUT `periods`: a WORKSPACE-WIDE sweep for every uncategorized counterparty, 50 rows per page plus the total, with a `next_cursor` for the page after this one. | |
| missing_ledger_only | No | A workspace-wide sweep for the counterparties that have a bank transaction and still need a ledger account (COA) default set for the direction their transactions take — the ledger-assignment worklist. It is its OWN scope: never pass it with `periods`, `uncategorized_only`, or `cursor`. Each row carries `needs_payable`/`needs_receivable` and the AP/AR defaults it holds now (a needed slot is empty), and rides in `ledger_rows` rather than `rows`. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Which SCOPE the call asked for; the row fields that are populated follow from it. `periods` whenever the call named months, whether or not it also filtered to the uncategorized ones. `missing_ledger_only` returns its rows in `ledger_rows`, not `rows`. | |
| rows | Yes | ||
| error | No | ||
| hints | No | ||
| success | Yes | ||
| next_step | No | What to do with the card this result renders. Added by the dispatcher when the card asks for a click. | |
| row_count | No | ||
| ledger_rows | No | ||
| next_cursor | No | The uncategorized sweep's next page: pass it back as `cursor`. Null when this page ends the sweep, absent on the periods scope, which pages nothing. | |
| total_count | No | Counterparties MATCHING the call, before the row cap, so a capped sweep says what it left out. On the periods scope: the DISTINCT counterparties `rows` names, and a multi-month call lists one counterparty on one row per month, so row_count can exceed it. Under `uncategorized_only` it counts the uncategorized ones alone; the scope's whole population is `categorized_count` plus `uncategorized_count`. Under `missing_ledger_only` it is the worklist actually returned and equals `row_count`: that scope reads the first 500 counterparties needing a default, so a worklist that fills 500 is a FLOOR, not a complete count. Assign those and read the scope again for the rest. | |
| workspace_id | No | ||
| base_currency | No | ||
| conversation_id | No | The conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation. | |
| periods_covered | No | The months the result covers, oldest first. | |
| categorized_count | No | COUNTERPARTIES of the scope that carry at least one category, counted over the whole scope, not over `rows`, and counted once however many months a counterparty appears in. Under `uncategorized_only` these are exactly the counterparties the result withheld, so a non-zero figure beside rows that are all uncategorized is the coverage, not a contradiction. | |
| resolved_workspace | No | The workspace that answered, when the caller named none and the token authorizes several. | |
| uncategorized_only | No | Whether `rows` holds ONLY the counterparties that carry no category. True on the workspace-wide sweep and on a period scope the call filtered. When true, `categorized_count` counts counterparties the result did NOT list. | |
| uncategorized_count | No | COUNTERPARTIES of the scope that carry none, counted the same way. This is the outstanding work; with `categorized_count` it is the scope's whole population. | |
| conversation_id_note | No | Present only when the server opened a fresh lane, stating that no choice recorded earlier was read. | |
| conversation_id_source | No | Where the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened. |