Query records from Well's database.
⚠️ WORKFLOW:
1. To SHOW the user a table of a record type, omit `fields` — you get the root's
display view in the Well web app's column order, trimmed on the widest roots to
the columns that fit a chat-width table. Prefer this whenever the user asks to
see/list/browse records rather than to answer a question about one specific
attribute. Ask for `fields` explicitly when you need a column it omits.
2. To answer a targeted question, call well_get_schema(root) FIRST to discover
available fields, then select ONLY the fields you need (5-15 typically).
ROOTS (read-only — all 32): companies, people, connectors, invoices, documents, transactions, accounts, payment_means, workspace_connectors, memberships, cards, checks, ledger_accounts, journals, journal_entries, tax_rates, exchange_rates, invoice_transactions, categories, account_balances, tasks, workspaces, invoice_payment_means, chat_conversations, blueprint_runs, workspace_connector_sync_logs, media, emails, phones, web_links, locations, invoice_items
(The accounting graph — ledger_accounts, journals, journal_entries — and balances/rates are read-only projections owned by the sync/posting pipelines; query them for financial context, you cannot create/update them here. Sub-resources like emails/phones/locations are usually richer when read via their parent company/person.)
CONNECTED TOOLS: do NOT use this tool to show the user what they have connected — call well_list_connectors instead. It owns that job: connection status, and an install link for anything not connected yet. Query root "workspace_connectors" here only for genuine RECORD-level needs — reading sync timestamps, filtering connections, joining them with other roots. ("connectors" is the installable catalog; "workspace_connector_sync_logs" is per-sync history.)
Well already syncs the providers' data into the roots above — invoices, transactions, accounts, the accounting graph. ALWAYS read it from here. well_invoke_connector_tool and a provider's own tools are for an ACTION the user explicitly asked to take on that provider (e.g. "create this record in Attio"), never a way to fetch data Well already holds.
EXAMPLE - Get all invoices for dashboard:
well_query_records({
root: "invoices",
fields: [
["invoices", "invoice_number"],
["invoices", "grand_total"],
["invoices", "issue_date"],
["invoices", "issuer", "name"],
["invoices", "receiver", "name"]
],
limit: 50
})
⚠️ RULES:
- Omitting fields (default view) or selecting specific fields both beat allFields
- Field paths from schema: "invoices.issuer.name" → ["invoices", "issuer", "name"]
- Default 50 records per request, max 500. Use cursor pagination for more.
PAGINATION (cursor-based):
- First call: omit cursor. Response includes nextCursor.
- Next page: pass the returned nextCursor as cursor.
- Last page: nextCursor is null.
Example:
Page 1: well_query_records({ root: "invoices", fields: [...], limit: 50 })
→ { rows: [...], nextCursor: "eyJpZCI6MTAwfQ==" }
Page 2: well_query_records({ root: "invoices", fields: [...], limit: 50, cursor: "eyJpZCI6MTAwfQ==" })
→ { rows: [...], nextCursor: null } // last page
FILTERING (whereClause):
- Uses Hasura-style operators on field names.
- Safe operators (work on ALL field types): _eq, _neq, _in, _nin, _is_null
- Numeric/date only: _gt, _gte, _lt, _lte
- Text only: _like, _ilike
- When unsure of a field's type, prefer _eq or _in (they always work).
- Combine with _and, _or, _not
- For relationship fields, use nested syntax: { "issuer": { "name": { "_ilike": "%acme%" } } }
Examples:
{ "status": { "_eq": "unpaid" } }
{ "grand_total": { "_gt": 1000 } }
{ "local_currency": { "_eq": "EUR" } }
{ "_and": [{ "status": { "_eq": "unpaid" } }, { "grand_total": { "_gte": 500 } }] }
{ "issuer": { "name": { "_ilike": "%acme%" } } }
SORTING (orderBy):
- Sort by any field: { field: "grand_total", direction: "desc" }
- Default sort is by primary key ascending.
Returns { rows, totalCount, nextCursor, success }.
Connector