List connectors
well_list_connectorsList the connectors a workspace can install AND everything it has already connected, each with a one-click install deep link. The result DRAWS THE CONNECT CARD the user clicks in.
It is also the answer to "which connectors can bring this provider's invoices in" (browser extension, direct connector, mailbox, file drive): pass counterparty_ids for the providers in question, or q to search one by name, instead of showing the missing-invoices worklist.
ONE tool answers both halves of the connect question — "what can I connect to Well?" and "what is connected, still syncing, or broken?" — because every existing connection is overlaid onto its catalog row. Do NOT read workspace_connectors records to work out connection coverage; this tool is that answer.
⚠️ FOR A SILENT COVERAGE CHECK, CALL well_get_connector_coverage INSTEAD. Same scope arguments, same rows, no card. A data skill confirming a bank is connected before it measures anything must use that one: this tool renders on every call, so a check run here drops a connect picker into a conversation about something else and then waits for a click nobody meant to make.
⚠️ WAIT ON THE CARD IN THE TURN THAT DREW IT. Write your one line for the user FIRST — the wait holds the turn open for up to a minute, and a user looking at a card with no sentence beside it has been given no reason to click — then call well_wait_for_selection on the kind this result names in next_step.
Each entry has:
service_id: the connector's stable catalog id (e.g. "stripe"), used in the install link.
name, category_id, direction: what the connector is.
data_domains: the financial domains it serves — any of "bank", "accounting", "invoicing" — or null for a non-financial connector. One connector can serve several domains (Qonto serves all three). "bank" here means the connector delivers cash movements, which a payroll or billing platform also does; do NOT read it as "this is a bank". To list banks, pass kind: "bank", which the server scopes on its own bank classification. data_domains is a finance filter for the connect steps, NOT the scope of what Well reads or changes in the tool: answer that from reads and writes.
reads: the Well record types Well reads from this tool, from the connector's declared catalog data (e.g. "invoice", "transaction", "people", "payslip"). Answer "what does Well read in ?" from this list and name only its items. An empty list means the catalog does not declare it yet: say you do not know yet ("je ne sais pas encore" in French). Never fill the gap from data_domains, invoice_source, category_id or the tool's name, and do not add them as a hint beside it.
writes: the exact provider actions Well may run in this tool from the chat, each only after the user confirms. An empty list means Well changes nothing in this tool from the chat: say so. Never name an action that is not on this list. When the user asks what Well reads or changes in a tool that is not connected (is_connected false), also give ONE install link, once, raw. When the top-level install_all_url is non-null (a slug lookup on an installable connector carries it), that link is the one to give, even for a single tool, and the row's install_url stays out of the answer; only when install_all_url is null give the row's install_url. Make no claim about what connecting it would bring in beyond reads.
invoice_source: this connector can bring supplier invoices into Well, either because it issues or holds them (an accounting or an invoicing tool) or because invoices arrive through it as files (a mailbox, a messaging app, a file drive). Read it to decide which tools to offer for a missing-invoice hunt. It is a property of the connector, not of this workspace's connection.
reason: why this row is on the card. "catalog" is the list that was asked for. "picked_vendor" is a connector behind a counterparty the user picked. "named_connector" is the one connector a slug argument named, or a connected row of that same brand that stands for it (an open-banking row beside it, or another of the brand's rows in its place). Say which is which; never present a catalog row as one the user chose.
status: "available" connectors are connectable now; "coming_soon"/"unavailable"/"maintenance" are not. These are codes for you: tell the person in words (coming soon, not offered, under maintenance), and never write the code or quote it.
is_matched / is_selected: whether this workspace's detected tools matched this connector / the workspace already picked it.
match_score: 0..1 confidence of that match; null when unmatched. It ranks nothing and ticks nothing: a detection is not a suggestion. It is internal: never show the score or its value to the person.
match_source: which detection lane matched the provider ("email", "transaction", "invoice", "tool", "accounting", "enrichment", "scoring", "crm", "bank", or "user" when the workspace picked it itself); null when there is no match or the match predates source tracking. A match found only in the inbox ("email") is never a reason to suggest a tool.
evidence: why Well suggests this tool, a list of { kind, count, count_is_lower_bound }; empty when Well holds none for the tool. A tool already connected carries empty evidence: it is never a suggestion. kind is "open_task" (Well has an open task to connect it), "payments" or "invoices" (count of payments or invoices with the tool's company in the last 12 months; count_is_lower_bound true reads "count+"), "user_pick" (the person picked it in Well), or "note" (a tool you passed in suggest). The list is ordered with the tools that have evidence first, the most payments and invoices ahead, then the rest by country and popularity.
suggestion_reason: your own one-line reason, echoed back, for a tool you passed in suggest; null on every other row, and always null for a tool already connected, which is never a suggestion. The server words no reason for payments, invoices, an open task or a pick: read the typed evidence and say it to the person yourself, in their language. Suggest a tool ONLY when its evidence is non-empty. A row with empty evidence is a catalog row, never a suggestion. When the result's evidence_complete is false, Well could not read every source: an empty row is then unchecked, so say you could not check and never say there is no sign yet.
is_connected: this workspace has a connection you should REPAIR or MANAGE, not install fresh. True for "enabled", "processing", "error" and "need_reconnect"; false for "to_configure" and "disabled", where a fresh install IS the right next step.
connection_status: the existing connection's state, or null when this workspace has no connection row for the connector at all. One of:
"enabled" — connected. The data stands as of last_successful_sync_at. This status never says a sync runs now: sync_in_progress does.
"processing" — connected, and a sync was started. It is the FIRST sync only when last_successful_sync_at is null; the data may then be partial. With a last_successful_sync_at, data has landed, from a routine refresh or from a first sync whose rows have landed: the data stands as of that instant, the newest rows can be missing, and a sync runs now only when sync_in_progress is true. Its tools stay live while it syncs: well_list_connector_tools and well_invoke_connector_tool run on it as on an "enabled" row, and a live read answers from the provider now. The records Well synced from it stand as of last_successful_sync_at: never call them complete while the row reads processing. Connected: do NOT ask the user to connect it again.
"error" — authenticated but its last real sync failed. Offer install_url as a reconnect when it is non-null. A null install_url means the grant is still live: state the failed sync, never a link.
"need_reconnect" — the grant is dead and only the user can restore it. Offer install_url as a reconnect, NOT a first install.
"to_configure" — a connect attempt that never completed its handshake. Nothing is connected: offer install_url as a first install, and never claim the tool is connected.
"disabled" — the connection was torn down. Offer install_url as a first install. A "degraded" connector never appears: it is resolved server-side against its own sync history into "enabled" or "error", so you never surface a state that clears itself. A connection whose state this build cannot read also reports null, and there is_connected stays true — read the two fields together, and treat "null status, is_connected true" as an existing connection whose health is unknown.
connect_failure_cause: WHY the connection is in a failed or refused state — one of the connect-failure vocabulary ("provider_rejected", "plan_required", "provider_billing_gated", "user_cancelled", "selected_not_authorised", …), or null while an attempt is live, on a healthy row, or when none was recorded. Use it to name the reason to the user instead of guessing from the status.
last_connect_outcome: {cause, at} — how this connector's most recent connect attempt ENDED, even when that attempt's row is gone (a cancelled or refused install removes its connection row, so connection_status and connect_failure_cause can read null while this still names the outcome). Read it to answer "the Ramp install said canceled" accurately: a "provider_rejected" cause means the PROVIDER refused the install, "plan_required" that the PROVIDER's own plan does not cover it, "connection_limit_reached" that WELL refused because this workspace's own Well plan has reached its bank connection limit (never the provider; the fix is on the Well plan), "user_cancelled" that the user closed the flow, "authorize_url_timed_out" that WELL gave the attempt up because the provider's sign-in page did not open in time (a slowness on Well's side, never the user's cancel; trying again usually works). Null when no attempt has ended recently.
sync_health: null, or { reading, summary } for a connection that is flagged degraded. connection_status answers whether the connection works; sync_health answers whether recent sync runs delivered everything. Quote the summary and do not turn it into a fault. "data_incomplete": some rows are incomplete or missing, so say the data is incomplete; when connection_status is "enabled" the connection works and a reconnect does not help. "runs_failing": recent sync runs are failing. "no_recent_sync": no run has succeeded recently. Advise a reconnect only when connection_status is "need_reconnect" or "error"; a non-null sync_health never calls for one on its own.
reconnect_reason: null, or why a "need_reconnect" connection lost its grant. "scope_insufficient": the grant is live but lacks a permission Well needs, so on the reconnect the user must accept every permission the tool asks for. "auth_revoked", "auth_missing" or "login_required": the grant expired, was revoked or was never completed, so the user signs in again. A new sign-in is all the user needs: give no step about which permissions to accept, because only "scope_insufficient" asks for one. "credential_rejected": the tool refused the stored API key, so the user pastes a new one. "account_choice_required": the user picks one account on the reconnect. Any other value: offer install_url as a reconnect and name no cause. Null on every other connection_status.
scope_coverage: null, or { state, missing_scopes, reconnect_url } on a live connection ("enabled" or "processing") whose requested permissions Well tracks (Gmail today). It answers whether the grant holds every permission Well asks for, which connection_status does not. "complete": it holds them all. "missing": the grant lacks the permissions listed in missing_scopes while the connection itself still works, so never call it broken. Say in one line that the tool is missing a permission, name it only from missing_scopes and never from a guess, then give reconnect_url once, raw, when it is non-null: it asks the same account for the permissions again on this same connection. It is the same link as reinstall_url on that row, so give one of the two, never both. When reconnect_url is null, say the permission is missing and give no link. "unknown": Well has not recorded this grant's permissions yet, so claim nothing either way and never ask for a reconnect on it.
workspace_connector_id: the connection instance's id, or null when there is no connection row. This is the id well_invoke_connector_tool and well_list_connector_tools need — resolve it HERE, never via well_query_records on workspace_connectors.
last_successful_sync_at: ISO timestamp of when data last landed (the end of the last finished sync, or the instant a first sync's rows landed while it still runs), or null when none has landed yet. An "enabled" connector with null here has a valid grant but has never delivered data.
sync_in_progress: true means a data sync is running right now: tell the user to wait rather than to act. False means Well found no running sync, whatever connection_status says: never say one runs. It holds for this read only: never repeat an earlier turn's sync state without a new read in this turn.
is_preselected: the card arrives with this one ticked. True ONLY on a from_selection result, where the row is a vendor the user themselves just picked, and on a slug lookup called with intent: "connect" — a detected match is a suggestion and is never pre-checked. A "to_configure" or "disabled" row can still be pre-checked — installing it IS the fix.
install_url: a one-click link that STARTS or REPAIRS the connection in Well. It works from any state — it signs the user in if needed, creates their workspace if they have none, then runs the connector's own auth flow — and it covers banks too (a bank opens its bank-login flow pre-selected). For a reconnect, give the user its install_url as is. Null when the connector is not "available", on every ai_client row (an AI app connects from its own settings, never through a link), and on a live connection — a connector still holding its grant ("enabled", "processing", or the live rows behind an "error" reading) has nothing for this link to start or repair, so a "reconnect it" ask on one is answered with its state and, when the row carries one, its reinstall_url. Hand this to the user to get started in one click.
reinstall_url: on a LIVE connection the requester owns, a link that asks the provider again for consent on that same connection, so a missing permission can be granted while the connection and its synced data stay. Null on every other row: a row that is not live repairs through install_url, a teammate's connection is never the requester's to reinstall, and only a connector whose live grant takes a new consent in place carries one (Gmail today). It is never a first install.
countries: the ISO 3166-1 alpha-2 countries this connector serves, or null when none is known. It is what the country scope sorts on; use it to explain why a bank fits the company, never to hide a bank the country field is null on.
direct_connector_service_id: on an open-banking (Plaid) row, the service_id of the bank's OWN connector when the bank has one a user can install now (e.g. "qonto" on a Qonto institution reached through Plaid); null on every other row. A connected row carrying it means the bank is reached through the aggregator although a direct connection exists: the direct row of that service_id is the offer. The field names a route, never a connection: read is_connected on the direct row before you offer it.
connection_paths: the rails this connector's brand can be installed over, drawn from the brand's installable members — "native_mcp" for the provider's native MCP server, "direct" for Well's connector over the provider API, and "open_banking" for an aggregator such as Plaid. Two or more distinct values mean the connect page lets the person choose the rail before installing; a single value means there is nothing to choose and the page goes straight to it. A link that names path= of its own already carries the choice, so it never re-asks.
unsent_document_counts is a TOP-LEVEL field, present only when include_unsent_counts was passed. It names every tool this workspace forwards documents to, with the documents each one has not received yet, biggest backlog first. IT IS THE ONLY PLACE THE BACKLOG IS REPORTED: that array carries the workspace's whole set of outbound connections whatever catalog page came back, the connector rows carry no count at all, and the catalog runs to hundreds of rows, so a tool with a real backlog is missing from any page that did not happen to carry it. An entry reading 0 is a tool that is up to date: say nothing about it. unsent_document_count_is_upper_bound true means a document filter applies to that connection, so the count is a maximum and reads as "up to ". Every count is read off Well's own forward record, so it measures what Well wrote down rather than what the tool confirmed. Name each tool by the entry's name.
unfinished_connects is a TOP-LEVEL field. Connect attempts in this workspace the person has not been told about yet, newest first. outcome is stopped (the person closed the connect before it finished), timed_out (nobody finished it within the hour), or still_connecting (it is still open). An empty array means there is nothing to tell; an absent field means nothing was read. Name a tool by its name. For each entry, say one short line in the reply: on stopped or timed_out, offer to connect it again or to skip it for now; on still_connecting, offer to wait or to skip it for now. Once the reply says the lines, call well_mark_connects_told with the workspace_connector_id of each entry it said, so a later read does not repeat them. An entry the reply did not say stays unmarked and comes back on the next read.
install_all_url is a TOP-LEVEL field, not a per-connector one. It is ONE link that installs every installable connector in this result that is not already connected, in the order they are listed. Every available, not-connected row also carries its own install_url, a connector the catalog holds by service id alone included, so a single row never needs this link to be installable. One exception: a row the catalog holds by service id alone (a long-tail bank institution) with a "need_reconnect", "error" or "to_configure" connection behind it carries NO install_url, because that link cannot name the existing connection and would start a second one for the same institution. Do not offer such a row a new install: state its connection_status and tell the user to repair the existing connection from Well, never promise a link for it. When the answer offers several connectors to install, hand the user install_all_url and do NOT list the per-connector install_url links beside it — the one link IS the whole offer, and a table of links beside it puts the reader back through several sign-ins. One link carries at most 10 connectors, and install_all_omitted names the service ids it left out, so offer those rows their own install_url. install_all_url is null when the result offers nothing to install. It is null too wherever the result names no set the user has chosen: the unfiltered catalog and the whole bank domain never carry the link, a name search carries it only when it matches exactly one connector, and an accounting or invoicing domain carries it only while the WHOLE result fits in one link and this page holds all of it — past that the link would stand for whichever rows the page happened to carry. A slug lookup carries it whenever the named connector is installable: its one-connector result always fits one link. When the one installable row offers two connection_paths, the link is that row's own slug entry — it reaches the page where the person picks the rail. from_selection always carries the link, however many vendors were picked, because the user named each one. Where install_all_url is null, the rows' own install_url links ARE the offer: list them, and never announce a batch link the result does not carry.
Paging: page with offset and page_count, never with the length of connectors. On the first page of an unsearched browse the workspace's ALREADY CONNECTED connectors are prepended so the catalog's ordering cannot bury them past any page you would ask for — so connectors can be longer than the page it came from, and page_count is the catalog window's own length. Advance by offset + page_count; total counts every matching connector across all pages. Those prepended rows carry is_connected true (or a to_configure/disabled state), so a workspace's live tools are visible without paging for them.
Scoping: pass kind ("bank" | "accounting" | "invoicing") to get only the connectors serving that domain — the whole set, server-ordered, including the long tail of bank institutions. Pass kind: "upload_surface" for the places invoices ARRIVE — mailboxes, messaging apps, file drives. Pass kind: "storage" for the drives Well FILES INTO — Google Drive, Dropbox, OneDrive — the step that asks where Well should write the documents it collects. Pass kind: "ai_client" for the AI apps that read Well over MCP: a row with is_connected true means that app is connected, and no row carries an install_url because an AI app connects from its own settings. Neither of those two is a financial domain: the server resolves each from the connectors' own display categories, so read the rows it returns and never re-derive the set from category_id yourself. They are opposite DIRECTIONS on the same drives, so a "storage" row carries direction "output" and no data_domains, and its is_connected reports the workspace's own file-drop connection, never the drive's separate invoice-source connection. Pass q to name-search the full catalog. Pass slug to resolve the ONE connector a request named: the card then shows that connector alone, whatever kind it is, ticked only when the call also passes intent: "connect". To answer "this tool, plus what I already have", pass kind ("bank", "accounting" or "invoicing") beside q or slug (e.g. slug "pennylane" with kind "accounting"): the first page then also carries the workspace's connected tools of that kind, with reason "catalog", ahead of the named tool. A named tool that no one can connect yet comes back as a row with its status and no install_url, never as a missing tool. When that connector is not connected or is owed a repair, and the workspace reaches the same bank through open banking with a better connection, the open-banking row comes back beside it. Outside the storage and ai_client scopes, every read (a search, an offset page, a pick and a slug included) shows a brand through its best-connected row: when another of the brand's own rows has a better connection than the row the catalog would show, that row comes back in its place, at the same position. Its slug and name can then differ from the ones the request named or searched for ("stripe-token" for "stripe"): it is the same tool, so report its is_connected and connection_status as the named tool's. Omit all of them for the curated view, which lists the tools with evidence first. Pass suggest with the tools a note the person gave you names, each with its one-line reason: those rows rank with the evidence and carry your reason. Use well_list_connector_tools for a live connection's actions.
Country: pass country (ISO 3166-1 alpha-2, e.g. "FR") on a connect-a-bank or a connect-an-accounting-tool step so the banks or accounting tools that serve the company's country sort first, then the ones that serve its region, then the rest. It reorders the page only — no row is dropped, and a connector the catalog carries no coverage for is left in place — so a connector the user names is still found with q. Take the country from the workspace identity; omit it when the country is unknown, and the order is unchanged.
Pass from_selection: true for the connect step that FOLLOWS a vendor pick. It returns the connectors behind the counterparties the user picked on the missing-invoices card in this conversation, and NOTHING else: only the picked vendors' connectors, and of those only the ones that can bring an invoice in (reason "picked_vendor"). It offers no accounting or invoicing tool the user did not pick: that offer belongs to its own step, scoped with kind. When the pick leaves no row, the list is empty and the card is not worth drawing. ⚠️ This tool draws its card on EVERY call, the empty one included, so never call it with from_selection to find out whether the pick has a connector behind it. Ask well_get_worklist_status({ worklist: "invoice_sources_for_pick" }) first: it draws nothing, and it reports how many of the picked vendors carry a connector that can bring an invoice in. Make the from_selection call only when that count is above zero. An ABSENT count is not a zero: the probe answers success: false when it could not read the pick at all, so retry it rather than reading its silence as a vendor with no connector. row_count reports the same number back on this result. picked_vendors_filtered counts the picked vendors' connectors that were dropped for bringing no invoices in: when it is above zero, say a filter ran rather than letting a short card read as a pick nobody made. It takes no q and no kind: those browse a catalog, and this names a set already decided. An empty list means this conversation holds no pick for this workspace, or no picked counterparty matched a connector.
Every result carries scope — "catalog", one of the three domains, "upload_surface", "storage", "ai_client", or "picked_vendors" — naming what the list IS. The card words its title from that field, so a caller must not describe the result as a domain the scope does not name.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| q | No | Name search across the full catalog (e.g. a specific bank). With a `kind` of "bank", "accounting" or "invoicing", the first page also carries the tools of that kind the workspace already has. Omit for the curated view, which lists the tools with evidence first. | |
| kind | No | Scope the card server-side. Three financial domains: "bank" (every bank and neobank, including the long tail of open-banking institutions, plus the platforms that hold an account like Qonto and Pennylane — never a payroll or billing tool that merely reports transactions), "accounting", and "invoicing". Plus two scopes the server resolves from display categories rather than from a financial domain: "upload_surface", the places invoices ARRIVE (mailboxes, messaging apps, file drives), and "storage", the drives Well FILES INTO (Google Drive, Dropbox, OneDrive). The last two are opposite directions on the same drives, so a workspace can hold both connections and each is offered on its own card. And "ai_client", the AI apps that read Well over MCP (Claude, Codex, the Well CLI and the like): read it to tell whether any AI app is connected. Its rows carry no install_url, since an AI app connects from its own settings. Use this for a connect-a-bank, a connect-where-invoices-arrive or a connect-where-Well-files step instead of filtering the default view yourself. Omit for every connectable connector. | |
| slug | No | Exact connector slug: resolves the ONE named connector, of any kind (e.g. "notion" for a connect-Notion request). Use it when the request names a single connector, instead of `q` which name-searches. With a `kind` of "bank", "accounting" or "invoicing" (e.g. slug "pennylane" with kind "accounting"), the result also carries the tools of that kind the workspace already has, so one read answers "this tool, plus what I already have". An unknown slug returns an empty list; retry with `q` on the name then. Cannot be combined with `q`, `from_selection`, `counterparty_ids`, or any other `kind`. | |
| limit | No | Max connectors to return (1-100, default 50). | |
| slugs | No | Exact connector slugs, one per tool the person named in one request (e.g. ["qonto", "pennylane"] for "connect Qonto and Pennylane"): resolves each named connector, and the result carries one `install_all_url` that installs every one of them that is not connected yet, in one browser tab. Use it instead of one call per tool when the request names two to 10 tools. A slug that matches nothing adds no row; retry that one tool with `q` on its name. Cannot be combined with `slug`, `q`, `kind`, `from_selection` or `counterparty_ids`. | |
| title | No | Heading for the connect card shown to the user, OVERRIDING the wording the card otherwise derives from the scope/kind. Use it to frame the step in its flow (e.g. "Connect your accounting tool for the close"). At most 120 characters. Omit to keep the default wording for the requested kind. | |
| intent | No | With `slug` or `slugs` only: "connect" ticks the named connectors on the card. Without it the card shows them unticked. Rejected on every other scope. | |
| offset | No | Number of connectors to skip, for paging (default 0). | |
| country | No | The company's country as an ISO 3166-1 alpha-2 code (e.g. "FR"). When set, the connectors that serve that country sort first, then the ones that serve its region, then the rest — the order only, no row is dropped. Use it on a connect-a-bank or a connect-an-accounting-tool step so the banks or accounting tools that fit the company appear first; take it from the workspace identity's country. Omit when the country is unknown, and the order is left unchanged. | |
| suggest | No | The tools you suggest from something the person told you, which only you can read (their notes, your memory of them, what they said earlier): each a catalog service_id and a one-line reason in the person's language ("You told me you bank with Qonto"). Those rows gain note evidence, rank with the other tools that have evidence, and carry your reason as their suggestion_reason. Never name a tool here from a guess, an email domain or a category alone. At most 10. | |
| subtitle | No | Supporting line under the connect card's heading, OVERRIDING the scope-derived subtitle. At most 240 characters. Omit to keep the default wording for the requested kind. | |
| 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. | |
| from_selection | No | Scope the card to the connectors behind the counterparties the user picked on the missing-invoices card in this conversation, each installable one pre-checked. Use it for the connect step that FOLLOWS a vendor pick. It returns those vendors' connectors and NOTHING else: a picked connector that brings no invoices in is dropped, and no accounting or invoicing tool the user did not pick is offered here: that offer is its own step, scoped with `kind`. Cannot be combined with `q` or `kind`: those name a catalog to browse, and this names a set already decided. Returns an empty list when this conversation holds no pick for this workspace, or when no picked counterparty matched a connector. | |
| 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. | |
| workspace_scope | No | Restrict this call to the family: the token's primary workspace plus the company workspaces under it that you are a member of. Unrelated authorized workspaces drop out of the read; row reads merge across the family, while a per-workspace figure still reports exactly one workspace. | |
| counterparty_ids | No | Scope the card to the connectors behind these counterparties, copied from the `company_id` of the missing-invoices rows. The explicit form of `from_selection`, for a caller holding the picked ids itself instead of a card click recorded in this session: it resolves the same connectors and filters them the same way. Passing counterparty_ids alone already scopes the card to the pick — from_selection is not needed alongside it; it cannot be combined with `q` or `kind`. | |
| include_unsent_counts | No | Add the top-level `unsent_document_counts`: every tool Well forwards this workspace's documents to, each with how many documents it has not received yet. That array is the whole answer — it holds every one of the workspace's outbound connections, whatever catalog page was requested, and the rows carry no count at all. Off by default, because it costs an extra read. The figure is the workspace's whole backlog, not a period's. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| error | No | ||
| limit | No | The page size that was REQUESTED. The catalog may return fewer. | |
| scope | No | What this result is a list OF: the requested kind, the picked vendors' connectors, or the curated catalog when neither was asked for. The card words itself from this, so it never describes the rows as a domain that was not requested. | |
| total | No | Every connector matching the query, across all pages — NOT the length of `connectors`. | |
| offset | No | How many catalog rows this page skipped. | |
| 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 | How many rows this result puts ON THE CARD, prepended rows included. `0` on a `picked_vendors` scope means the pick has no connector behind it that can bring an invoice in: the card carries nothing to tick, so say so in half a sentence and move on. Not a paging cursor — `page_count` is. | |
| connectors | No | ||
| page_count | No | The catalog page's own length, and the ONLY safe paging cursor: advance by `offset + page_count`. `connectors` can be LONGER — on the first page of an unsearched browse the workspace's already-connected rows are prepended so they cannot be lost to the catalog's ordering — so paging by the array's length silently skips exactly that many catalog rows on every later request. | |
| 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. | |
| install_all_url | Yes | One link that installs every installable connector in this result. Null when the result offers nothing to install, or when its scope names a set the reader has not chosen. When it is non-null it is the ONLY install link the answer offers — do not list the rows' own install_url beside it. When it is null, the rows' own install_url is the offer instead. | |
| newly_connected | No | Tools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. The connected-line rule says when to tell an entry; when it does, one line per entry, in the person's language: "<name> is connected.". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later. | |
| connector_request | No | Present only on WhatsApp, on a `q` or `slug` lookup that found no row the person can connect: the request card's own read of the named tool, the fields `well_show_connector_request` returns. Well sends its line and its request option under your message. | |
| evidence_complete | No | False when Well could not read every source of evidence for this workspace. A row with empty `evidence` is then UNCHECKED, not clean: say you could not check, and never say there is no sign yet. True or absent means every source was read. Only a catalog read (no scope, or a `kind` of `bank`, `accounting` or `invoicing`, with or without `q` or `slug`) reads evidence: the picked-vendor (`from_selection`, `counterparty_ids`), `upload_surface`, `storage` and `ai_client` scopes read no workspace evidence. A row holds only a note you passed in `suggest`, otherwise empty `evidence`. These scopes always report false. | |
| resolved_workspace | No | The workspace that answered, when the caller named none and the token authorizes several. | |
| extension_installed | No | Present on a `well_get_connector_coverage` read only. Whether the person who asks has the Well browser extension in THIS workspace: `installed`, `missing` or `unknown`. The catalog rows never carry the extension, so read this field, never a records query on workspace_connectors. `installed`: this person opened this workspace in Well with the extension in their Chrome. Well cannot see an uninstall, so a browser hand-off can still stop; report that stop as it happens. `missing`: nobody has opened this workspace in Well with the extension, so a step that runs in a browser cannot run for this person yet; say so before you hand it off. `unknown`: Well cannot tell for this caller, for example when another member's extension is on record and this person has none; never say the extension is installed or missing, run the step and report what happens. The answer is for this person in this workspace only: another member's extension never counts as this person's, and the same person can read `missing` in another workspace. | |
| install_all_omitted | Yes | The service ids install_all_url could not carry, because one link names a bounded number of connectors. Offer these rows their own install_url instead of promising the batch link covers them. | |
| unfinished_connects | No | Connect attempts in this workspace the person has not been told about yet, newest first. `outcome` is `stopped` (the person closed the connect before it finished), `timed_out` (nobody finished it within the hour), or `still_connecting` (it is still open). An empty array means there is nothing to tell; an absent field means nothing was read. Name a tool by its `name`. For each entry, say one short line in the reply: on `stopped` or `timed_out`, offer to connect it again or to skip it for now; on `still_connecting`, offer to wait or to skip it for now. Once the reply says the lines, call `well_mark_connects_told` with the `workspace_connector_id` of each entry it said, so a later read does not repeat them. An entry the reply did not say stays unmarked and comes back on the next read. | |
| 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. | |
| payment_link_providers | No | Present on a `well_get_connector_coverage` read only. The providers (`stripe`, `qonto`) whose connection in THIS workspace can make an invoice payment link today, read from what each connection's token can reach. A connected, synced row that is missing here cannot make a link: never promise one for it. An absent field means the read did not run, which is not a provider that can make a link. | |
| unsent_document_counts | No | Every tool this workspace forwards documents to, each with the documents it has not received yet, biggest backlog first. Present only when `include_unsent_counts` was set. THIS IS THE ONLY PLACE THE BACKLOG IS REPORTED: it is not a page, it carries the workspace's whole set of outbound connections whether or not the requested catalog page holds their rows, and the catalog rows carry no count. An empty array means the workspace forwards to nothing; an absent field means nothing was measured. `unsent_document_count_is_upper_bound: true` means a document filter applies to that connection, so the count is a maximum and reads as `up to <n>`. Every count is read off Well's own forward record, so it measures what Well wrote down rather than what the tool confirmed. Name a tool by its `name`. An entry reading `0` is a tool that is up to date: say nothing about it. | |
| picked_vendors_filtered | No | How many of the picked vendors' connectors were dropped for bringing no invoices in. Present on the `picked_vendors` scope only. Above zero means the card is SHORTER than the pick: say that those vendors' tools cannot deliver an invoice, rather than letting the gap read as a pick the user never made. |