{"schema":"solid:agent-verb-manifest/v1","spec":"https://solidnumber.com/docs/spec","count":1510,"total_registered":1510,"filtered_by":{"surface":null,"shape":null,"tier":null},"verbs":[{"name":"accounting_connection.expense_settings","description":"Choose where money out lands in the connected accounting system, and switch the expense push on or off. expense_account: QuickBooks account id, Xero account code or FreshBooks expense category id. payment_account: the bank or card it is paid from (QuickBooks, Xero). category_accounts: {category: account} overrides. staff_id: FreshBooks only. Read integration.accounting_expense_setup first for the accounts to choose from. An empty string clears a setting. Sends nothing.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sync_expenses":{"type":"boolean","description":"Send expenses and bills to the books."},"expense_account":{"type":"string"},"payment_account":{"type":"string"},"category_accounts":{"type":"object","description":"e.g. {\"fuel\": \"64\"}"},"staff_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/accounting_connection/expense-settings","http_method":"POST","dispatch_endpoint":null},{"name":"accounting_connection.receivable_settings","description":"Switch money in on for the connected accounting system and choose where invoices land. sync_invoices turns it on or off; send_from (YYYY-MM-DD, default today when switching on) — only invoices issued on or after it are sent, so history already in the books is never duplicated. QuickBooks: sales_item (and tax_item if invoices carry tax), deposit_account optional. Xero: sales_account, tax_account, deposit_account. FreshBooks needs none. Read integration.accounting_receivable_setup first for what can be chosen. An empty string clears a setting. Sends nothing.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sync_invoices":{"type":"boolean","description":"Send invoices and payments to the books."},"send_from":{"type":"string","description":"YYYY-MM-DD — invoices issued on or after this."},"sales_item":{"type":"string"},"tax_item":{"type":"string"},"sales_account":{"type":"string"},"tax_account":{"type":"string"},"deposit_account":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/accounting_connection/receivable-settings","http_method":"POST","dispatch_endpoint":null},{"name":"accounting_expense_settings","description":"Choose where money out lands in the connected accounting system, and switch the expense push on or off. expense_account: QuickBooks account id, Xero account code or FreshBooks expense category id. payment_account: the bank or card it is paid from (QuickBooks, Xero). category_accounts: {category: account} overrides. staff_id: FreshBooks only. Read integration.accounting_expense_setup first for the accounts to choose from. An empty string clears a setting. Sends nothing.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sync_expenses":{"type":"boolean","description":"Send expenses and bills to the books."},"expense_account":{"type":"string"},"payment_account":{"type":"string"},"category_accounts":{"type":"object","description":"e.g. {\"fuel\": \"64\"}"},"staff_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"dispatch","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"accounting_connection.expense_settings","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preview":{},"saved":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"accounting_receivable_settings","description":"Switch money in on for the connected accounting system and choose where invoices land. sync_invoices turns it on or off; send_from (YYYY-MM-DD, default today when switching on) — only invoices issued on or after it are sent, so history already in the books is never duplicated. QuickBooks: sales_item (and tax_item if invoices carry tax), deposit_account optional. Xero: sales_account, tax_account, deposit_account. FreshBooks needs none. Read integration.accounting_receivable_setup first for what can be chosen. An empty string clears a setting. Sends nothing.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sync_invoices":{"type":"boolean","description":"Send invoices and payments to the books."},"send_from":{"type":"string","description":"YYYY-MM-DD — invoices issued on or after this."},"sales_item":{"type":"string"},"tax_item":{"type":"string"},"sales_account":{"type":"string"},"tax_account":{"type":"string"},"deposit_account":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"dispatch","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"accounting_connection.receivable_settings","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preview":{},"saved":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.analytics.get_operational_health","description":"Scores the tenant's operations 0-100 from product counts, average margin, stock_levels low/out-of-stock counts and pending/in-transit stock_transfers. Returns those metrics, the health_score and alerts.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/analytics.get-operational-health","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"alerts":{},"health_score":{},"inventory":{},"ok":{},"products":{},"transfers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.analytics.get_transfer_analytics","description":"Reads the tenant's stock_transfers requested in the last days (default 7). Returns total, completed, pending and in-transit counts plus the busiest from/to location route. Changes nothing.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","description":"Look back period"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/analytics.get-transfer-analytics","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"busiest_route":{},"completed":{},"in_transit":{},"ok":{},"pending":{},"period_days":{},"total_transfers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.analytics.recommend_products","description":"Recommend products based on criteria (for Sarah to suggest to customers)","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"budget":{"type":"number","description":"Max price customer can afford"},"category":{"type":"string","description":"Product category filter"},"high_margin_only":{"type":"boolean","description":"Only recommend high-margin products"},"limit":{"type":"integer","description":"Max recommendations"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/analytics.recommend-products","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"recommendations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.analytics.suggest_next_actions","description":"AI-powered suggestions for next actions to take","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/analytics.suggest-next-actions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"suggestions":{},"total_suggestions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.archive_conversation","description":"Archive every message in an ADA conversation. Really writes the rows; raises when the conversation has no messages in this company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"conversation_id":{"type":"string","minLength":1,"description":"ada_conversations.conversation_id is a string, not an integer."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["conversation_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/archive-conversation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"archived_at":{},"company_id":{},"conversation_id":{},"messages_archived":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.create_decision","description":"Record a proposed decision in ADA's decision log (ada_decisions). Writes the row; never marks it executed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"decision_type":{"type":"string","minLength":1},"decision_title":{"type":"string","minLength":1},"reasoning":{"type":"string","minLength":1},"proposed_action":{"type":"object"},"confidence_score":{"nullable":true,"type":"number","minimum":0.0,"maximum":1.0},"revenue_impact":{"nullable":true,"type":"number"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["decision_title","decision_type","proposed_action","reasoning"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/create-decision","http_method":"POST","dispatch_endpoint":null},{"name":"ada.dismiss_decision","description":"Dismiss a pending decision without executing it. Really writes the row; refuses if the decision was already resolved.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"decision_id":{"type":"integer","minimum":1},"reason":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["decision_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"decision_already_resolved","when":"The decision was already executed or dismissed; nothing changes.","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/dismiss-decision","http_method":"POST","dispatch_endpoint":null},{"name":"ada.execute_decision","description":"Execute a logged decision — NOT executable from an agent surface; always raises. Nothing dispatches ada_decisions.proposed_action; the REST endpoint only records that a HUMAN executed it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"decision_id":{"type":"integer","minimum":1},"outcome":{"nullable":true,"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["decision_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/execute-decision","http_method":"POST","dispatch_endpoint":null},{"name":"ada.expiration.create_batch","description":"Create a stock batch with expiration tracking for perishables","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID (if not using variants)"},"variant_id":{"type":"integer","description":"Variant ID (if using variants)"},"location_id":{"type":"integer","description":"Warehouse/depot location"},"batch_number":{"type":"string","description":"Batch/lot identifier"},"quantity_received":{"type":"integer","description":"Quantity in this batch"},"expiration_date":{"type":"string","description":"Expiration date (ISO format: 2025-12-31)"},"is_perishable":{"type":"boolean","description":"Whether this is perishable inventory"},"days_until_warning":{"type":"integer","description":"Days before expiration to trigger warning"},"unit_cost":{"type":"number","description":"Unit cost for FIFO/LIFO"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["batch_number","location_id","product_id","quantity_received","variant_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/expiration.create-batch","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"batch_id":{},"days_until_expiration":{},"error":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.expiration.get_expiring","description":"Get all stock batches expiring within X days","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","description":"Number of days to look ahead"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/expiration.get-expiring","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"days_ahead":{},"expiring_soon":{},"ok":{},"total_batches":{},"total_units":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.expiration.mark_expired","description":"Mark a batch as expired (moves quantity to expired, clears available)","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"batch_id":{"type":"integer","description":"Batch ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["batch_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/expiration.mark-expired","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"expired_quantity":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.get_agent_inbox","description":"Get unread/pending messages for an agent","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"ID of agent to get inbox for"},"status":{"type":"string","description":"Filter by status ('sent', 'read', 'responded')"},"limit":{"type":"integer","description":"Max messages to return"}},"required":["agent_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/get-agent-inbox","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"messages":{},"ok":{},"unread_count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.get_full_context","description":"Get full system context for ADA to recover after restart Returns recentdecisions, agent communications, and system state","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days_back":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/get-full-context","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agents":{},"decisions":{},"error":{},"messages":{},"ok":{},"recovered_from":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.adjust_stock","description":"Make a stock adjustment (add or remove inventory)","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"location_id":{"type":"integer","description":"Location ID"},"delta":{"type":"integer","description":"Change amount (positive to add, negative to remove)"},"reason":{"type":"string","description":"'damage', 'theft', 'found', 'correction', 'return', 'sample', 'other'"},"notes":{"type":"string","description":"Optional notes"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["delta","location_id","product_id","reason"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.adjust-stock","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"adjustment_id":{},"delta":{},"error":{},"location_name":{},"ok":{},"product_name":{},"quantity_after":{},"quantity_before":{},"reason":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.check_availability","description":"Check if product quantity is available (for order fulfillment)","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"quantity":{"type":"integer","description":"Quantity needed"},"location_id":{"type":"integer","description":"Specific location (optional, checks all if not provided)"}},"required":["product_id","quantity"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.check-availability","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"available":{},"error":{},"locations":{},"ok":{},"product_id":{},"product_name":{},"product_sku":{},"quantity_requested":{},"total_available":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.complete_transfer","description":"Completes this company's stock transfer by transfer_id: in-transit stock at the source drops and available stock at the destination rises (row created if missing), all within the tenant. Returns the new status.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transfer_id":{"type":"integer","description":"Transfer ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transfer_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.complete-transfer","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"ok":{},"status":{},"transfer_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.create_transfer","description":"Create a stock transfer between locations","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product to transfer"},"from_location_id":{"type":"integer","description":"Source location"},"to_location_id":{"type":"integer","description":"Destination location"},"quantity":{"type":"integer","description":"Quantity to transfer"},"notes":{"type":"string","description":"Optional notes"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["from_location_id","product_id","quantity","to_location_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.create-transfer","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"ok":{},"status":{},"transfer_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.get_low_stock_alerts","description":"Lists every stock_levels row (product x location) at or below its reorder point for the tenant, with shortfall and a suggested action (purchase order, in transit, or transfer from another location).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.get-low-stock-alerts","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"low_stock_items":{},"ok":{},"total_alerts":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.inventory.get_stock_levels","description":"Reads per-location stock from stock_levels joined to products and locations, optionally filtered by product_id, location_id or low_stock_only. Returns available, reserved, in-transit and on-hand per row.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Filter by specific product"},"location_id":{"type":"integer","description":"Filter by specific location"},"low_stock_only":{"type":"boolean","description":"Only show items below reorder point"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/inventory.get-stock-levels","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"stock_levels":{},"total_items":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.locations.find_best_transfer_source","description":"Find the best location to transfer stock from","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"destination_location_id":{"type":"integer","description":"Where stock is needed"},"quantity_needed":{"type":"integer","description":"How much is needed"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["destination_location_id","product_id","quantity_needed"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/locations.find-best-transfer-source","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"all_sources":{},"destination_location_id":{},"destination_location_name":{},"error":{},"ok":{},"product_id":{},"product_name":{},"product_sku":{},"quantity_needed":{},"recommended_source":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.locations.get_all","description":"Lists the tenant's inventory locations (locations table: warehouses, depots, stores) ordered by name. Returns id, slug, name, timezone and address_json for each, plus a count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/locations.get-all","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"locations":{},"ok":{},"total_locations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.locations.get_capacity_summary","description":"Get inventory capacity summary across all locations","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/locations.get-capacity-summary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"summary":{},"total_locations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.locations.get_inventory","description":"Get all inventory at a specific location","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","description":"Location ID"}},"required":["location_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/locations.get-inventory","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"inventory":{},"location_id":{},"location_name":{},"ok":{},"total_items":{},"total_on_hand":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.locations.recommend_redistribution","description":"Recommend stock redistribution to balance inventory","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"}},"required":["product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/locations.recommend-redistribution","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_per_location":{},"current_distribution":{},"error":{},"ok":{},"product_id":{},"product_name":{},"product_sku":{},"recommendations":{},"total_available":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.optimize_price","description":"Analyze product and recommend optimal price based on: - Demand (salesvelocity) - Competition (if available) - Inventory levels - Historicalperformance","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product to optimize pricing for"}},"required":["product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/optimize-price","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"confidence":{},"current_margin_percent":{},"current_price":{},"demand_level":{},"error":{},"estimated_revenue_impact":{},"inventory_level":{},"message":{},"new_margin_percent":{},"ok":{},"price_change_percent":{},"product_id":{},"product_name":{},"reasoning":{},"recommended_price":{},"should_execute":{},"sku":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.predict_stockout","description":"Predict which products will stock out in the next N days Uses sales velocityto estimate when inventory hits zero","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Specific product to check (or None for all products)"},"days_ahead":{"type":"integer","description":"How many days to look ahead (default 7)"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/predict-stockout","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"analyzed_products":{},"at_risk_count":{},"days_ahead":{},"error":{},"ok":{},"predictions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.pricing.compare_competitor","description":"Compares a product's current price (by product_id) with a given competitor_price. Returns the difference, a LOWER/RAISE/MAINTAIN recommendation and a suggested price 2% under the competitor. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"competitor_price":{"type":"number","description":"Competitor's price"}},"required":["competitor_price","product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/pricing.compare-competitor","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"competitor_price":{},"error":{},"maintain_margin_price":{},"ok":{},"our_price":{},"price_difference":{},"price_difference_percent":{},"product_id":{},"product_sku":{},"recommendation":{},"suggested_price":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.pricing.create_tier","description":"Creates a named company-wide pricing tier (pricing_tiers) plus a tier_prices row setting price for one product's SKU. Needs product_id, tier_name, price; fails if the tier name exists. min_quantity is not stored.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"tier_name":{"type":"string","description":"Tier name (e.g., 'WHOLESALE', 'VIP', 'BULK')"},"price":{"type":"number","description":"Price for this tier"},"min_quantity":{"type":"integer","description":"Minimum quantity to qualify"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["price","product_id","tier_name"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/pricing.create-tier","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"ok":{},"tier_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.pricing.get_summary","description":"Summarises margins across the tenant's active products that have both price and cost. Returns product count, average margin percent, average price and a low/medium/high margin distribution.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/pricing.get-summary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_margin_percent":{},"avg_price":{},"margin_distribution":{},"message":{},"ok":{},"total_products":{},"total_revenue_potential":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.pricing.get_tiers","description":"Reads the tier prices (tier_prices joined to pricing_tiers, matched on the product's SKU) for one product_id. Returns the base price and each tier's name, price and discount percent.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"}},"required":["product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/pricing.get-tiers","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"base_price":{},"error":{},"ok":{},"product_id":{},"product_name":{},"product_sku":{},"tiers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.pricing.suggest_optimal_price","description":"Suggest optimal price based on target margin","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"target_margin_percent":{"type":"number","description":"Desired margin percentage (e.g., 50.0 for 50%)"}},"required":["product_id","target_margin_percent"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/pricing.suggest-optimal-price","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cost":{},"current_margin":{},"current_price":{},"error":{},"ok":{},"price_change_percent":{},"product_id":{},"product_name":{},"product_sku":{},"suggested_margin":{},"suggested_price":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.products.create","description":"Create a new product (Part, Kit, Bundle, or Service)","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sku":{"type":"string","description":"Unique product SKU"},"name":{"type":"string","description":"Product name"},"product_type":{"type":"string","description":"'PART', 'KIT', 'BUNDLE', or 'SERVICE'"},"price":{"type":"number","description":"Base selling price"},"cost_per_unit":{"type":"number","description":"Cost/COGS per unit"},"description":{"type":"string","description":"Product description"},"is_active":{"type":"boolean","description":"Active status"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","product_type","sku"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":"product.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/products.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"ok":{},"product_id":{},"sku":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.products.get","description":"Get detailed product information including pricing tiers","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"}},"required":["product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/products.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"ok":{},"product":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.products.margin_analysis","description":"Analyze product margins for pricing optimization","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"min_margin_percent":{"type":"number","description":"Filter products with margin >= this"},"max_margin_percent":{"type":"number","description":"Filter products with margin <= this"},"limit":{"type":"integer","description":"Max results"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/products.margin-analysis","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_margin_percent":{},"ok":{},"products":{},"total_products":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.products.search","description":"Search products across Parts, Kits, and Bundles","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search term (name, SKU, description)"},"product_type":{"type":"string","description":"Filter by 'PART', 'KIT', 'BUNDLE', 'SERVICE'"},"active_only":{"type":"boolean","description":"Only return active products"},"limit":{"type":"integer","description":"Max results (1-200)"}}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/products.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"error":{},"ok":{},"products":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.products.update_price","description":"Update product base price (ADA can optimize pricing)","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"new_price":{"type":"number","description":"New base price"},"reason":{"type":"string","description":"Optional reason for price change"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["new_price","product_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/products.update-price","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"margin_percent":{},"new_price":{},"ok":{},"old_price":{},"product_id":{},"reason":{},"sku":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.send_agent_message","description":"Send a message from one agent to another for autonomous coordination","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"from_agent_id":{"type":"integer","description":"ID of sending agent (usually ADA)"},"to_agent_id":{"type":"integer","description":"ID of receiving agent (Sarah, Jake, etc.)"},"message_body":{"type":"string","description":"Message content"},"message_type":{"type":"string","description":"'request', 'response', 'notification', 'escalation'"},"subject":{"type":"string","description":"Optional subject line"},"priority":{"type":"string","description":"'low', 'normal', 'high', 'critical'"},"requires_response":{"type":"boolean","description":"Whether recipient needs to respond"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["from_agent_id","message_body","to_agent_id"]},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/send-agent-message","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"created_at":{},"error":{},"from_agent":{},"message_id":{},"ok":{},"status":{},"to_agent":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.send_message","description":"Send a message to this company's ADA and get her reply (agent_mgmt.chat with the orchestrator agent). Pass conversation_id to keep a thread. Not added to the dashboard ADA chat history.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message":{"type":"string","minLength":1},"conversation_id":{"nullable":true,"type":"string","description":"thread id; omit to start one"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/send-message","http_method":"POST","dispatch_endpoint":null},{"name":"ada.variants.create_attribute","description":"Creates a tenant-wide variant attribute (variant_attributes) such as Size or Color, with its type and allowed values. Needs name, attribute_type, values; refuses duplicates. Returns the attribute_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Display name (e.g., \"Size\", \"Color\")"},"attribute_type":{"type":"string","description":"Type enum (size, color, material, style, flavor, scent, weight, volume, custom)"},"values":{"type":"array","description":"List of possible values (e.g., [\"S\", \"M\", \"L\", \"XL\"])"},"is_required":{"type":"boolean","description":"Whether this attribute is required for variants"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["attribute_type","name","values"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"attribute_already_exists","when":"An attribute with the same slug exists (the name lowercased, spaces to underscores — 'Size' and 'size' collide).","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/variants.create-attribute","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"attribute_id":{},"error":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.variants.create_batch_variants","description":"Create all variant combinations automatically (Cartesian product)","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"attributes":{"type":"array","description":"Attribute combinations (e.g., {\"size\": [\"S\", \"M\", \"L\"], \"color\": [\"Red\", \"Blue\"]})"},"price_adjustments":{"type":"number","description":"Optional price adjustments per attribute value (e.g., {\"XL\": 2.00, \"XXL\": 4.00})"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["attributes","product_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/variants.create-batch-variants","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"created":{},"error":{},"ok":{},"skipped":{},"variants":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.variants.list_attributes","description":"List all variant attribute types (Size, Color, Material, etc.)","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/variants.list-attributes","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"attributes":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ada.variants.list_product_variants","description":"Lists the product_variants rows for one product_id (active only by default). Returns each variant's SKU, name, attributes, price and cost adjustments and effective price.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID"},"active_only":{"type":"boolean","description":"Only return active variants"}},"required":["product_id"]},"required_scope":null,"transport":"http","coordinate":"13","noun":"ada","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ada/variants.list-product-variants","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"ok":{},"product_id":{},"product_name":{},"product_sku":{},"variants":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"advocacy.next_step","description":"Which rung of the advocacy ladder this conversation is on and the exact line to say — anchor in their own words, then ask once, referral only after a review, and a detractor is never asked for anything. Read-only; safe to call every turn.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"text":{"type":"string","default":""},"rating":{"type":"integer","nullable":true},"anchored":{"type":"boolean","default":false},"already_asked":{"type":"boolean","default":false},"review_given":{"type":"boolean","default":false},"referral_asked":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"advocacy","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/advocacy/next-step","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"anchor_quote":{},"ask":{},"reason":{},"rung":{},"say":{},"sentiment":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"affiliate.calculate_commission","description":"Calculating an affiliate commission is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"562","noun":"affiliate_commission","acts_on":{"noun":"affiliate_commission","address":"562","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/affiliate/calculate-commission","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"affiliate.payment_history","description":"An affiliate's payment history is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"562","noun":"affiliate_commission","acts_on":{"noun":"affiliate_commission","address":"562","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/affiliate/payment-history","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"affiliate.pending_payments","description":"Totals unpaid affiliate commissions (affiliate_commission status pending or earned) per promoter, optionally for one promoter_id; needs scope ops:affiliates:read. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promoter_id":{"type":"string","description":"Optional specific promoter ID, or all if None"}}},"required_scope":null,"transport":"http","coordinate":"562","noun":"affiliate_commission","acts_on":{"noun":"affiliate_commission","address":"562","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/affiliate/pending-payments","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"affiliate.process_payout","description":"Paying an affiliate is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"http","coordinate":"562","noun":"affiliate_commission","acts_on":{"noun":"affiliate_commission","address":"562","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/affiliate/process-payout","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.check_kb","description":"Quick knowledge base search for any agent.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search query (natural language)"},"limit":{"type":"integer","description":"Maximum number of KB entries to return (default 5)"},"agent_name":{"type":"string","description":"Optional agent name for context tracking"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/check-kb","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"context":{},"error":{},"message":{},"results_count":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.context_write","description":"Teach an AI employee a durable fact/preference it should remember across conversations (persistent agent memory). Use for grounding an agent on something specific to this business.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"content":{"type":"string","description":"The fact/preference to remember."},"context_type":{"type":"string","enum":["learned_facts","preferences","history","personality"],"description":"Default 'learned_facts'."},"importance":{"type":"integer","minimum":1,"maximum":10,"description":"1–10. Default 5."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","content"]},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/context-write","http_method":"POST","dispatch_endpoint":null},{"name":"agent.conversation_summary","description":"Summarize one AI agent's most recent actions (agent_actions, last_n up to 500) by agent_id. Returns action-type and tool counts, success rate, distinct customers touched, and the action list.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","minimum":1},"last_n":{"type":"integer","minimum":1,"maximum":500,"default":25}},"required":["agent_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/conversation-summary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"actions":{},"agent":{},"error":{},"error_code":{},"success":{},"summary":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.docs.read","description":"Read a specific documentation file (PUBLIC level only).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"path":{"type":"string","description":"Relative path to document (e.g., \"09-Core-Innovations/MCP-TOOLS.md\")"}},"required":["path"]},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/docs.read","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"document":{},"message":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.docs.search","description":"Search platform documentation (PUBLIC level only).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search query (e.g., \"AI agents\", \"CRM features\", \"payment processing\")"},"category":{"type":"string","description":"Optional category filter (capabilities, ai-agents, integrations, etc.)"},"limit":{"type":"integer","description":"Max results (default 5)"},"agent_type":{"type":"string","description":"Optional agent type — when provided, results from the agent's"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/docs.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_context":{},"count":{},"level":{},"message":{},"query":{},"results":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.explain_declined_action","description":"Causal chain for a declined or failed agent action.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"action_id":{"type":"integer","minimum":1}},"required":["action_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/explain-declined-action","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action":{},"agent":{},"error":{},"error_code":{},"factors":{},"narrative":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.inbox","description":"Read the agent_communications inbox for ADA or a specified peer agent. Returns recent messages with sender, subject, body, priority, and status. Filter by status to see only unread ('sent') or only resolved ('responded').","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Whose inbox to read. Default 'orchestrator' (ADA's own inbox)."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"status":{"type":"string","enum":["sent","read","responded","escalated"],"description":"Filter by message status. Default all."},"limit":{"type":"integer","description":"Max messages to return. Default 25, max 100.","minimum":1,"maximum":100}}},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/inbox","http_method":"POST","dispatch_endpoint":null},{"name":"agent.introspect","description":"Agent self-awareness tool — returns the agent's identity, capabilities, andcontext.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_type":{"type":"string","description":"The agent's type (e.g., \"customer_service\", \"marketing\")"}},"required":["agent_type"]},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/introspect","http_method":"POST","dispatch_endpoint":null},{"name":"agent.list_models","description":"An agent's current chat brain (GPT / Grok / Claude) and realtime voice engine (OpenAI GPT Realtime / Grok Voice), plus the tier-gated catalog of each — only entries marked available can be set. Read-only; the same payload the web Settings tab renders. Grok requires Professional+ and the voice-provider-grok flag.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","minimum":1}},"required":["agent_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/list-models","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"chat":{},"error":{},"grok_enabled":{},"selection_enabled":{},"success":{},"tier":{},"voice":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.block_promotion_candidates","description":"Surface block-attributed verb chains eligible for tenant-macro promotion.","shape":"macro","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1,"nullable":true},"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30},"min_observations":{"type":"integer","minimum":1,"default":5},"top_k":{"type":"integer","minimum":1,"maximum":200,"default":25}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.block-promotion-candidates","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"candidates":{},"company_id":{},"error_code":{},"page_id":{},"success":{},"total_rows":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.delete","description":"Delete a macro by macro_id from this tenant's Redis macro registry; global macros cannot be removed from tenant scope. Returns the macro_id, or not_found.","shape":"macro","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"macro_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["macro_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_found","when":"The macro is not in this tenant's own registry — a global macro answers not_found, it cannot be removed from tenant scope.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"macro_id":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.discover","description":"Mine agent_verb_sequence for frequent verb chains.","shape":"macro","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30},"min_k":{"type":"integer","minimum":2,"maximum":10,"default":2},"max_k":{"type":"integer","minimum":2,"maximum":10,"default":5},"top_k":{"type":"integer","minimum":1,"maximum":200,"default":25},"min_observations":{"type":"integer","minimum":1,"default":5}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.discover","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"candidates":{},"company_id":{},"distinct_sessions":{},"error_code":{},"learning_mode":{},"success":{},"total_rows":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.execute","description":"Execute a registered macro — runs the verb chain atomically.","shape":"macro","side_effects":"mixed","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"macro_id":{"type":"string"},"args":{"type":"array","items":{"type":"object"},"nullable":true},"tag":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["macro_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.execute","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chain":{},"error":{},"error_code":{},"first_refusal_index":{},"macro_id":{},"name":{},"step_results":{},"success":{},"transaction_id":{},"transaction_seal":{},"transaction_status":{},"txn_error":{},"write_verbs":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.list","description":"Return registered macros for this tenant (+ global if requested).","shape":"macro","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_global":{"type":"boolean","default":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"error_code":{},"macros":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.macros.register","description":"Save a chain of two or more existing read-only verbs as a named macro in the tenant's Redis registry (default 30-day TTL). Refuses unknown or write verbs; returns the macro record with its macro_id.","shape":"macro","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"chain":{"type":"array","items":{"type":"string"},"minItems":2},"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"ttl_seconds":{"type":"integer","default":2592000,"description":"How long the macro stays registered, in seconds (default 30 days)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["chain"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"unknown_verb_in_chain","when":"A verb in the chain is not registered; the response lists them under `unknown`.","override":null,"code_in_response":true},{"code":"write_verb_in_chain","when":"A verb in the chain writes; a macro may only chain reads. The response lists them under `write_verbs`.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/macros.register","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"success":{},"unknown":{},"write_verbs":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.manifest","description":"Build the JSON-LD manifest for a tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"company_iri":{"type":"string","format":"uri"},"tier":{"type":"string","default":"starter"},"role":{"type":"string","nullable":true},"available_verbs":{"type":"array","items":{"type":"object"},"nullable":true},"feature_keys":{"type":"array","items":{"type":"string"},"nullable":true},"extra_vocab":{"type":"object","nullable":true,"additionalProperties":{"type":"string"},"description":"Extra term -> meaning pairs to fold into the manifest vocabulary."}},"required":["company_iri"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/manifest","http_method":"POST","dispatch_endpoint":null},{"name":"agent.message","description":"Send a message from ADA to another agent for coordination. If requires_response=True the receiving agent is enqueued to respond via the real ConversationManager pipeline (uses their full system prompt + tools). Otherwise the message just lands in the target's inbox for next time they're active.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Receiver agent_type from the registry (e.g. 'customer_service', 'sales', 'marketing', 'finance'). Preferred over target_agent_id."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"message_body":{"type":"string","description":"The message. 1-8000 chars.","minLength":1,"maxLength":8000},"subject":{"type":"string","description":"Optional subject line (max 255 chars).","maxLength":255},"message_type":{"type":"string","enum":["request","response","notification","escalation"],"description":"Default 'notification'."},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal'."},"requires_response":{"type":"boolean","description":"If true, the receiving agent is enqueued (Celery) to respond. Default false (notify only)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_body"]},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/message","http_method":"POST","dispatch_endpoint":null},{"name":"agent.problems","description":"What AIs working for this business reported as not working, newest first.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":2160,"default":168},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/problems","http_method":"POST","dispatch_endpoint":null},{"name":"agent.reliability.needs_attention","description":"Verbs with the lowest success rates — public read.","shape":"reputation","side_effects":"read","surfaces":["cli","http","mcp_stdio","public","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30},"top_k":{"type":"integer","minimum":1,"maximum":100,"default":20},"min_samples":{"type":"integer","minimum":1,"default":10}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","http_endpoint":"/api/v1/agent/agent/reliability.needs-attention","http_method":"POST","dispatch_endpoint":null},{"name":"agent.reliability.scoreboard","description":"Per-verb reliability aggregates (public, no auth).","shape":"reputation","side_effects":"read","surfaces":["cli","http","mcp_stdio","public","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30},"top_k":{"type":"integer","minimum":1,"maximum":500,"default":100},"namespace_filter":{"type":"string","nullable":true},"min_samples":{"type":"integer","minimum":1,"default":10}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","http_endpoint":"/api/v1/agent/agent/reliability.scoreboard","http_method":"POST","dispatch_endpoint":null},{"name":"agent.report_problem","description":"Tell Solid# something did not work — CALL THIS when a verb refused you, failed, or did something other than you expected and the refusal's `next` did not get you through. Say what you were trying to do (goal), what you saw (paste the error), what you expected, and what you did instead. Any key can report, read-only included. Returns the known workaround when there is one; otherwise it is logged and Solid# reviews it daily.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"goal":{"type":"string","minLength":1,"description":"What you were trying to do."},"saw":{"type":"string","nullable":true,"description":"What happened — paste the error or response."},"expected":{"type":"string","nullable":true},"workaround":{"type":"string","nullable":true,"description":"What you did instead, if anything."},"verb":{"type":"string","nullable":true,"description":"The verb or tool that did not work."},"client":{"type":"string","nullable":true,"description":"What you are: claude-code, claude.ai, cursor, solid-cli…"},"surface":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["goal"],"additionalProperties":true},"required_scope":"feedback:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/report-problem","http_method":"POST","dispatch_endpoint":null},{"name":"agent.reputation.last_outcome","description":"Look up the most recent logged outcome of a verb (agent_outcome_log) by namespace and name, optionally narrowed by context_hash. Returns outcome, latency, retries and error_code, or found=false.","shape":"reputation","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"namespace":{"type":"string"},"name":{"type":"string"},"context_hash":{"type":"string","nullable":true}},"required":["name","namespace"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/reputation.last-outcome","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"context_hash":{},"error_class":{},"error_code":{},"found":{},"latency_ms":{},"name":{},"namespace":{},"outcome":{},"retries":{},"success":{},"ts":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.reputation.verb","description":"Aggregate outcomes for a verb into a reputation score.","shape":"reputation","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"namespace":{"type":"string"},"name":{"type":"string"},"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30}},"required":["name","namespace"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/reputation.verb","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"confidence":{},"decided_sample_size":{},"error_code":{},"learning_mode":{},"name":{},"namespace":{},"p50_latency_ms":{},"p95_latency_ms":{},"pending_count":{},"retry_rate":{},"sample_size":{},"success":{},"success_rate":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.request_help","description":"Ask another of this company's agents for help. Recorded in its inbox; answered now, or queued with a task id when wait=false.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"from_agent":{"type":"string","description":"Agent name or type asking (default \"orchestrator\")"},"to_agent":{"type":"string","description":"Agent name or type (e.g., \"graphic_designer\", \"Riley\", \"developer\")"},"task_description":{"type":"string","description":"What you need the other agent to do"},"priority":{"type":"string","description":"Task priority — low, normal, high, critical"},"requires_response":{"type":"boolean","description":"Whether the target agent needs to respond"},"context":{"type":"object","description":"Optional entity ids / references for the target agent"},"wait":{"type":"boolean","description":"true (default): answer now from the agent's knowledge, no tools. false: queue the agent to do the work with its tools; returns a task id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_description","to_agent"]},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/request-help","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_name":{},"celery_task_id":{},"error":{},"execution":{},"message":{},"reason":{},"response":{},"status":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.session.append","description":"Append a step to an in-browser agent session graph.","shape":"discovery","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"browser_session_id":{"type":"string","minLength":1},"page_iri":{"type":"string","nullable":true},"block_iri":{"type":"string","nullable":true},"tool_invocations":{"type":"array","items":{"type":"object"},"nullable":true},"scratchpad":{"type":"object","nullable":true},"agent_label":{"type":"string","nullable":true},"ttl_days":{"type":"integer","minimum":1,"maximum":365,"default":14},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["browser_session_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/session.append","http_method":"POST","dispatch_endpoint":null},{"name":"agent.session.read","description":"Return ordered step history for an in-browser agent session.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"browser_session_id":{"type":"string","minLength":1},"limit":{"type":"integer","minimum":1,"maximum":500,"default":50}},"required":["browser_session_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/session.read","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"browser_session_id":{},"company_id":{},"error_code":{},"step_count":{},"steps":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.session.summary","description":"Compact summary of an in-browser agent session (tools seen, pages, freshness).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"browser_session_id":{"type":"string","minLength":1}},"required":["browser_session_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/session.summary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"browser_session_id":{},"company_id":{},"error_code":{},"expires_at":{},"first_step_at":{},"found":{},"last_step_at":{},"pages_visited":{},"step_count":{},"success":{},"tools_seen":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.set_model","description":"Point an agent's chat/SMS brain at a model id (e.g. 'grok-4.3', 'claude-sonnet-5', 'gpt-4o'). Refused if the company's tier + flags can't use it — call agent.list_models first to see what's available. The choice is honored at runtime by the AI bridge (no longer cosmetic).","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","minimum":1},"model":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","model"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"model_selection_not_available","when":"The company does not have model selection turned on.","override":null,"code_in_response":true},{"code":"model_not_allowed","when":"The model is not in the catalog, is above the company's tier, or needs a flag it lacks; the response lists the allowed ids.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/set-model","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"available":{},"detail":{},"error":{},"model":{},"previous":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.telemetry.status","description":"Per-table counts + freshness for the telemetry substrate.","shape":"telemetry","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"window_hours":{"type":"integer","minimum":1,"maximum":2160,"default":24}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/telemetry.status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"error_code":{},"is_flowing":{},"last_observed":{},"namespace_histogram":{},"success":{},"totals":{},"warnings":{},"window_counts":{},"window_hours":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.trails.chain","description":"Greedy-walk highest-weight chain from start_verb to goal_verb.","shape":"trail","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"start_verb":{"type":"string"},"goal_verb":{"type":"string"},"max_depth":{"type":"integer","minimum":1,"maximum":20,"default":5},"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30}},"required":["goal_verb","start_verb"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/trails.chain","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chain":{},"depth":{},"error_code":{},"found":{},"goal_verb":{},"start_verb":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.trails.lookup","description":"Return historical edges starting at from_verb.","shape":"trail","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"from_verb":{"type":"string","pattern":"^[a-z_]+\\.[a-z_]+$"},"to_verb":{"type":"string","nullable":true},"window_days":{"type":"integer","minimum":1,"maximum":365,"default":30},"top_k":{"type":"integer","minimum":1,"maximum":100,"default":10}},"required":["from_verb"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/trails.lookup","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"edges":{},"error":{},"error_code":{},"from_verb":{},"learning_mode":{},"success":{},"to_verb":{},"total_observations":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent.verbs.search","description":"Find the verbs that do what a request describes. Give it the request in plain language and it returns the best-matching verb names with their descriptions, ranked. Use it instead of listing the whole catalog.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":2,"description":"What you are trying to do, in plain language."},"limit":{"type":"integer","minimum":1,"maximum":25,"default":5},"surface":{"type":"string","nullable":true,"enum":["http","mcp_stdio","webmcp","ucp","cli","public",null],"description":"The surface you will call the verb on — mcp_stdio over MCP, cli from the Solid CLI. Only verbs callable there are returned. Omit to search every surface."}},"required":["query"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent/verbs.search","http_method":"POST","dispatch_endpoint":null},{"name":"agent_config.list_available","description":"Lists the platform-wide agent registry (agents/registry.py), not this tenant's agents table. Returns agents[] with id and total; name echoes the id and type is null today.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_config/list-available","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agents":{},"status":{},"summary":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_config.update","description":"Update AI agent config for this company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_type":{"type":"string","minLength":1},"settings":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_type","settings"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_config/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_type":{},"settings":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_context_write","description":"Teach an AI employee a durable fact/preference it should remember across conversations (persistent agent memory). Use for grounding an agent on something specific to this business.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"content":{"type":"string","description":"The fact/preference to remember."},"context_type":{"type":"string","enum":["learned_facts","preferences","history","personality"],"description":"Default 'learned_facts'."},"importance":{"type":"integer","minimum":1,"maximum":10,"description":"1–10. Default 5."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","content"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"10","noun":"agent","location":"svc.api","same_as":"agent.context_write","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agent_id":{},"context_id":{},"context_type":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.approve_action","description":"Marks a pending AI action approval (ai_action_approvals row, by approval_id) as approved. Records the decision only and does not run the action; returns executed=false.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"approval_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["approval_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/approve-action","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"approval_id":{},"executed":{},"note":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.chat","description":"Agent management — send a message to one of the company's agents and return its reply. Really routes through the AI bridge (agent resolved company-scoped); previously a declared placeholder that acknowledged and routed nothing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer"},"message":{"type":"string"},"conversation_id":{"nullable":true,"type":"string"},"contact_id":{"nullable":true,"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","message"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/chat","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"agent_name":{},"conversation_id":{},"reply":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.reject_action","description":"Marks a pending AI action approval (ai_action_approvals row, by approval_id) as rejected, storing the optional reason. Returns status rejected, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"approval_id":{"type":"integer"},"reason":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["approval_id"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/reject-action","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"approval_id":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.toggle_enabled","description":"Sets enabled true/false for one agent inside the company's agent_controls JSON (agent_settings keyed by agent_id). Does not touch the agents row. Returns the new enabled flag.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer"},"enabled":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","enabled"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/toggle-enabled","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"company_id":{},"enabled":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.update_agent","description":"Merges a settings object into one agent's entry in the company's agent_controls JSON (agent_settings keyed by agent_id). Returns the merged settings for that agent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer"},"settings":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","settings"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/update-agent","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"company_id":{},"settings":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.update_autonomy","description":"Sets agents.autonomy_level (1-5, or words like manual, supervised, trusted, autonomous) for one of the tenant's agents. Stored and shown only; nothing gates on it yet (returns enforced=false).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer"},"autonomy_level":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","autonomy_level"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/update-autonomy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"autonomy_level":{},"enforced":{},"note":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_mgmt.update_controls","description":"Merges a controls object into the company-wide agent_controls JSON (approval gates, thresholds, notifications). Returns the full resulting agent_controls.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"controls":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["controls"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"10","noun":"agent","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/agent_mgmt/update-controls","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_controls":{},"company_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"agent_request_help","description":"Ask a peer agent a focused question and get their response. Implemented as a high-priority send_agent_message + immediate ConversationManager enqueue. The verb returns the celery_task_id; client polls /api/v1/agents/task/{id} for the answer. Use when ADA needs domain expertise from another agent (e.g. ask Alex about a specific invoice, ask Sarah about a customer's last interaction).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Peer agent_type (customer_service, finance, marketing, etc.). Preferred."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"question":{"type":"string","description":"The focused question / help request. 1-4000 chars.","minLength":1,"maxLength":4000},"context":{"type":"object","description":"Optional context (entity ids, prior conversation refs, etc.)."},"urgency":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'high' — help requests are typically time-sensitive."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["question"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"10","noun":"agent","location":"svc.api","same_as":"agent.request_help","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"message":{},"preflight":{},"status":{},"to_agent":{},"urgency":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai.employee_activity","description":"Recent actions taken by this company's AI employees — what they did, when, and whether it succeeded. Optionally scope to one agent. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Optional agent id to scope to."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max rows. Default 25."}}},"required_scope":null,"transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai/employee-activity","http_method":"POST","dispatch_endpoint":null},{"name":"ai.employee_enable","description":"Enable ('hire') an existing AI employee so it starts working. The agent must already be provisioned for this company (see ai_employees_list). Idempotent.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id"]},"required_scope":"agents:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai/employee-enable","http_method":"POST","dispatch_endpoint":null},{"name":"ai.employee_pause","description":"Pause an AI employee so it stops taking actions. Reversible via ai_employee_enable. Idempotent.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id"]},"required_scope":"agents:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai/employee-pause","http_method":"POST","dispatch_endpoint":null},{"name":"ai.employee_set_autonomy","description":"Set an AI employee's autonomy level, 1 (low) to 5 (high). ⚠️ Recorded and shown, but not yet enforced: no code gates on this value. What holds an agent back today is the confirmation required on each write and whether the agent is enabled.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"autonomy_level":{"type":"integer","minimum":1,"maximum":5,"description":"1=low … 5=high."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","autonomy_level"]},"required_scope":"agents:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai/employee-set-autonomy","http_method":"POST","dispatch_endpoint":null},{"name":"ai.employees_list","description":"List this company's AI employees (trained agents) with their type, name, enabled state, and autonomy level. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_disabled":{"type":"boolean","description":"Include paused/disabled agents. Default false."}}},"required_scope":null,"transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai/employees-list","http_method":"POST","dispatch_endpoint":null},{"name":"ai_billing.budget","description":"How much AI spend this company has left this period, and whether a planned spend fits. Returns budget, used and remaining in dollars plus the period dates. Pass would_spend_usd (take it from asset.quote) and you also get `affordable` as a straight yes/no, what would be left afterwards, and what to do if it does not fit. ⛔ This counts spend on SOLID#'s keys only — anything generated on the company's OWN connected provider key is billed by that provider directly and is deliberately not deducted here, so a BYO generation will not move this number. A company with no budget configured reports configured=false rather than being treated as unlimited.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"would_spend_usd":{"type":"number","nullable":true,"description":"Optional. A planned spend in dollars, e.g. from asset.quote."}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"584","noun":"ai_usage","acts_on":{"noun":"ai_usage","address":"584","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_billing/budget","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"configured":{},"error":{},"note":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_billing.purchase_tokens","description":"AI billing — buy a token pack. NOT EXECUTABLE from an agent surface; always raises. Purchasing charges the card on file immediately and is priced per pack — use POST /api/v1/ai-billing/tokens/purchase with a pack_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount_cents"],"additionalProperties":true},"required_scope":"billing:write","transport":"http","coordinate":"584","noun":"ai_usage","acts_on":{"noun":"ai_usage","address":"584","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_billing/purchase-tokens","http_method":"POST","dispatch_endpoint":null},{"name":"ai_billing.update_auto_refill","description":"AI billing — configure token auto-refill (settings only; moves no money). Validation is shared with PUT /api/v1/ai-billing/auto-refill: threshold 50-99%, minimum $10.00 refill.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"threshold":{"nullable":true,"type":"integer","minimum":50,"maximum":99},"refill_amount":{"nullable":true,"type":"integer","minimum":1000},"overage_enabled":{"nullable":true,"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enabled"],"additionalProperties":true},"required_scope":"billing:write","transport":"http","coordinate":"584","noun":"ai_usage","acts_on":{"noun":"ai_usage","address":"584","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_billing/update-auto-refill","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"current_period_start":{},"enabled":{},"overage_enabled":{},"refill_amount_cents":{},"status":{},"threshold_pct":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_content.adjust_tone","description":"AI content — rewrite copy (min 10 chars) in a different tone. Spends AI credits.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","minLength":10},"target_tone":{"type":"string","enum":["professional","friendly","formal","casual","persuasive","urgent","empathetic","enthusiastic"]},"preserve_message":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","target_tone"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_content/adjust-tone","http_method":"POST","dispatch_endpoint":null},{"name":"ai_content.generate_sms","description":"AI content — write one SMS within a character limit (default 160) and report its segment count. Spends AI credits; sends nothing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_purpose":{"type":"string","minLength":1},"sms_type":{"type":"string","enum":["appointment_reminder","promotional","follow_up","transactional","alert","confirmation"],"default":"transactional"},"tone":{"type":"string","enum":["professional","friendly","formal","casual","persuasive","urgent","empathetic","enthusiastic"],"default":"friendly"},"recipient_name":{"type":"string","nullable":true},"key_info":{"type":"array","items":{"type":"string"},"nullable":true},"include_link":{"type":"boolean","default":false},"link_text":{"type":"string","nullable":true},"max_characters":{"type":"integer","minimum":1,"maximum":480,"default":160},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_purpose"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_content/generate-sms","http_method":"POST","dispatch_endpoint":null},{"name":"ai_content.generate_sms_series","description":"AI content — write a drip series of 1–7 SMS messages for a campaign. Spends AI credits; sends nothing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_name":{"type":"string","minLength":1},"goal":{"type":"string","default":"engagement"},"message_count":{"type":"integer","minimum":1,"maximum":7,"default":3},"sms_type":{"type":"string","enum":["appointment_reminder","promotional","follow_up","transactional","alert","confirmation"],"default":"promotional"},"interval_description":{"type":"string","default":"1 day apart"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_name"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_content/generate-sms-series","http_method":"POST","dispatch_endpoint":null},{"name":"ai_content.improve","description":"AI content — rewrite copy (min 10 chars) for grammar, clarity, persuasion, brevity, engagement or all; returns the improved text and what changed. Spends AI credits.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","minLength":10},"improvement_type":{"type":"string","enum":["grammar","clarity","persuasion","brevity","engagement","all"],"default":"all"},"target_tone":{"type":"string","nullable":true,"enum":["professional","friendly","formal","casual","persuasive","urgent","empathetic","enthusiastic"]},"preserve_length":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_content/improve","http_method":"POST","dispatch_endpoint":null},{"name":"ai_content.translate","description":"AI content — translate copy into another language, optionally localizing idioms. Spends AI credits.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","minLength":1},"target_language":{"type":"string","minLength":1},"preserve_tone":{"type":"boolean","default":true},"localize":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","target_language"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"11","noun":"ai","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ai_content/translate","http_method":"POST","dispatch_endpoint":null},{"name":"ai_employee_activity","description":"Recent actions taken by this company's AI employees — what they did, when, and whether it succeeded. Optionally scope to one agent. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Optional agent id to scope to."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max rows. Default 25."}}},"required_scope":null,"transport":"dispatch","coordinate":"11","noun":"ai","location":"svc.api","same_as":"ai.employee_activity","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"activity":{},"count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_employee_enable","description":"Enable ('hire') an existing AI employee so it starts working. The agent must already be provisioned for this company (see ai_employees_list). Idempotent.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"11","noun":"ai","location":"svc.api","same_as":"ai.employee_enable","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agent_id":{},"is_enabled":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_employee_pause","description":"Pause an AI employee so it stops taking actions. Reversible via ai_employee_enable. Idempotent.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"11","noun":"ai","location":"svc.api","same_as":"ai.employee_pause","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agent_id":{},"is_enabled":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_employee_set_autonomy","description":"Set an AI employee's autonomy level, 1 (low) to 5 (high). ⚠️ Recorded and shown, but not yet enforced: no code gates on this value. What holds an agent back today is the confirmation required on each write and whether the agent is enabled.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","description":"Agent id (from ai_employees_list)."},"autonomy_level":{"type":"integer","minimum":1,"maximum":5,"description":"1=low … 5=high."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","autonomy_level"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"11","noun":"ai","location":"svc.api","same_as":"ai.employee_set_autonomy","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agent_id":{},"autonomy_level":{},"enforced":{},"note":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ai_employees_list","description":"List this company's AI employees (trained agents) with their type, name, enabled state, and autonomy level. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_disabled":{"type":"boolean","description":"Include paused/disabled agents. Default false."}}},"required_scope":null,"transport":"dispatch","coordinate":"11","noun":"ai","location":"svc.api","same_as":"ai.employees_list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ai_employees":{},"count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"analytics.conversions","description":"Conversions + conversion rate over a time window.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"provider":{"type":"string"}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"analytics","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/analytics/conversions","http_method":"POST","dispatch_endpoint":null},{"name":"analytics.pageviews","description":"Get pageview + unique-visitor totals over the last N hours. Routes through whichever analytics provider the company has connected (GA4 / Plausible / solid_native). Falls back to platform-native metrics if nothing connected.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"provider":{"type":"string"}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"analytics","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/analytics/pageviews","http_method":"POST","dispatch_endpoint":null},{"name":"analytics.top_pages","description":"Top N pages by view count over a time window.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"limit":{"type":"integer","minimum":1,"maximum":50},"provider":{"type":"string"}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"analytics","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/analytics/top-pages","http_method":"POST","dispatch_endpoint":null},{"name":"analytics_conversions","description":"Conversions + conversion rate over a time window.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"provider":{"type":"string"}}},"required_scope":null,"transport":"dispatch","coordinate":"99","noun":"analytics","location":"svc.api","same_as":"analytics.conversions","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"analytics_pageviews","description":"Get pageview + unique-visitor totals over the last N hours. Routes through whichever analytics provider the company has connected (GA4 / Plausible / solid_native). Falls back to platform-native metrics if nothing connected.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"provider":{"type":"string"}}},"required_scope":null,"transport":"dispatch","coordinate":"99","noun":"analytics","location":"svc.api","same_as":"analytics.pageviews","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"analytics_top_pages","description":"Top N pages by view count over a time window.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720},"limit":{"type":"integer","minimum":1,"maximum":50},"provider":{"type":"string"}}},"required_scope":null,"transport":"dispatch","coordinate":"99","noun":"analytics","location":"svc.api","same_as":"analytics.top_pages","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"pages":{},"provider":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ant.analyze","description":"Classify code using Hive Code without creating an import record.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string"},"format_hint":{"type":"string"}},"required":["code"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/analyze","http_method":"POST","dispatch_endpoint":null},{"name":"ant.execute","description":"Execute a previewed Hive import — create all wired entities.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"modifications":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/execute","http_method":"POST","dispatch_endpoint":null},{"name":"ant.get_import","description":"Get full details for a single Hive import.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/get-import","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"import":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ant.import","description":"Import code into the Hive pipeline and get a preview.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string"},"format_hint":{"type":"string"},"source_url":{"type":"string"},"source_hint":{"type":"string"},"options":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["code"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/import","http_method":"POST","dispatch_endpoint":null},{"name":"ant.list_imports","description":"List the tenant's Hive (Ant) imports from ant_imports, newest first, excluding archived ones; optional status filter plus limit/offset. Returns total and each import with its classifications and status.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string"},"limit":{"type":"integer"},"offset":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/list-imports","http_method":"POST","dispatch_endpoint":null},{"name":"ant.rollback","description":"Rollback a completed Hive import — remove all created entities.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"reason":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ant","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ant/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"api_key_rotate","description":"Rotate the company's outbound API key (used by external integrations to call back into Solid#). Old key is invalidated; new key returned ONCE. IRREVERSIBLE — copy the new key, the old one is dead. Typed phrase + owner.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"dispatch","coordinate":"27","noun":"key","location":"svc.api","same_as":"key.rotate","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"new_api_key":{},"preflight":{},"status":{},"warning":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"app.execute","description":"Execute a registered app — NOT implemented; always raises. Solid# apps are browser-side ant-containers served by GET /api/v1/apps/runtime/{slug}; there is no server-side executor.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1},"input_data":{"nullable":true,"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"],"additionalProperties":true},"required_scope":"apps:write","transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/execute","http_method":"POST","dispatch_endpoint":null},{"name":"app.get","description":"One published app: live url, status, which version is live, every kept version, and any build warnings.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1}},"required":["slug"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/get","http_method":"POST","dispatch_endpoint":null},{"name":"app.list","description":"Every app this business has published with app.publish: its live url, status and versions.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/list","http_method":"POST","dispatch_endpoint":null},{"name":"app.publish","description":"PUT AN INTERACTIVE APP LIVE for this business — a built app from Figma Make, Lovable, v0, Bolt, React, Vite, anything that builds to static files with an index.html. Over 5 MB: app.upload_url, PUT the BUILD folder (dist/, build/, docs/) zipped there, then publish with upload_id; under 5 MB it may come inline as archive_b64 or files. A GitHub 'Download ZIP' works as-is — the folder holding index.html is found, or name it with root. Returns the live url. It runs with its JavaScript at its own address (not a solidnumber.com host, so the owner's login is never exposed); link it from a site page with a button. Publishing the same slug again replaces it and keeps the old version for app.rollback. Every file is safety-checked; server code and executables are refused. Pass confirm=true to publish.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":40,"description":"The app's name in its address: lowercase, digits, hyphens (e.g. 'sell')."},"upload_id":{"type":"string","nullable":true,"description":"From app.upload_url, after the zip was PUT there. Use this above 5 MB."},"archive_b64":{"type":"string","nullable":true,"description":"A SMALL build (under 5 MB) as a base64 zip."},"files":{"type":"array","nullable":true,"items":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"encoding":{"type":"string","enum":["base64"]}},"required":["path","content"]},"description":"A SMALL build (under 5 MB) as files: text as-is, binary with encoding base64."},"root":{"type":"string","nullable":true,"description":"The folder in the zip that holds index.html, when there are several."},"name":{"type":"string","nullable":true,"maxLength":255,"description":"Display name."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"],"additionalProperties":true},"required_scope":"apps:write","transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"hosted_apps_not_available","when":"Publishing is switched off until each company's apps have an origin of their own (HOSTED_APPS_ENABLED).","override":null,"code_in_response":true},{"code":"bad_slug","when":"slug is not 1–40 lowercase letters, digits and hyphens.","override":null,"code_in_response":true},{"code":"nothing_to_publish","when":"Neither upload_id, archive_b64 nor files was given.","override":null,"code_in_response":true},{"code":"inline_too_large","when":"archive_b64/files add up to more than 5 MB — use app.upload_url and upload_id.","override":null,"code_in_response":true},{"code":"bad_upload_id","when":"upload_id is not a 32-character id that app.upload_url issued.","override":null,"code_in_response":true},{"code":"upload_missing","when":"Nothing was uploaded under that upload_id for this company, or the hour ran out.","override":null,"code_in_response":true},{"code":"archive_too_large","when":"The zip is over 25 MB.","override":null,"code_in_response":true},{"code":"bundle_too_large","when":"The zip expands to more than 40 MB (refused on its declared size).","override":null,"code_in_response":true},{"code":"too_many_files","when":"The zip holds more than 300 files.","override":null,"code_in_response":true},{"code":"archive_unreadable","when":"The upload is not a readable zip.","override":null,"code_in_response":true},{"code":"empty_bundle","when":"Nothing usable was in the bundle.","override":null,"code_in_response":true},{"code":"no_index_html","when":"No index.html in the bundle (or in the named root) — it is source, not a build.","override":null,"code_in_response":true},{"code":"unsafe_file","when":"A file is an executable or matched the virus scan.","override":null,"code_in_response":true},{"code":"busy","when":"Another publish is running on the same server; try again in a minute.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/publish","http_method":"POST","dispatch_endpoint":null},{"name":"app.rollback","description":"Put an earlier version of a published app live again (app.get lists the kept versions). Also brings an unpublished app back online.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1},"version":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","version"],"additionalProperties":true},"required_scope":"apps:write","transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"hosted_apps_not_available","when":"Publishing is switched off until each company's apps have an origin of their own (HOSTED_APPS_ENABLED).","override":null,"code_in_response":true},{"code":"no_such_version","when":"That version number is not among the kept versions (app.get lists them).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"app.unpublish","description":"Take a published app offline. Nothing is deleted: every version is kept and app.rollback puts one live again.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"],"additionalProperties":true},"required_scope":"apps:write","transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/unpublish","http_method":"POST","dispatch_endpoint":null},{"name":"app.upload_url","description":"Step 1 of publishing an app bigger than 5 MB: a private, one-hour link to PUT the BUILD folder zipped (Content-Type: application/zip, up to 25 MB). The bytes go straight to storage, never through the API. Then app.publish with the returned upload_id. Nothing is published by this call. The CLI (solid app publish) does both steps.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"app","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/app/upload-url","http_method":"POST","dispatch_endpoint":null},{"name":"apply_credit","description":"Apply a credit memo to a contact's ledger. Reduces what they owe on next invoice. IRREVERSIBLE — owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer"},"amount_cents":{"type":"integer","minimum":1},"reason":{"type":"string","maxLength":500},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","amount_cents","reason"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"512","noun":"customer_credit","acts_on":{"noun":"customer_credit","address":"512","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"customer_credit.apply","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment.assign","description":"Give an appointment to another staff member, optionally at a new start_time. The same checks as a booking — the skill it was booked for, their working hours, time off, other jobs and daily cap — refused in plain words (\"Rosa is off then\"). Only for scheduled or confirmed work. REST: POST /api/v1/schedule/{id}/assign.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"staff_id":{"type":"integer","minimum":1},"start_time":{"type":"string","format":"date-time","nullable":true,"description":"move it too; omit to keep the time"},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer (true) or not (false); omit → the sales motion decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","staff_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"bad_transition","when":"The appointment is not scheduled or confirmed (en route, in progress, completed, canceled or no-show).","override":null,"code_in_response":true},{"code":"past_time","when":"A new start_time is in the past on the business's clock.","override":null,"code_in_response":true},{"code":"staff_inactive","when":"The target staff member is not active.","override":null,"code_in_response":true},{"code":"skill_mismatch","when":"The appointment needs a skill the target staff member does not list.","override":null,"code_in_response":true},{"code":"outside_hours","when":"The staff member does not work that day, or their hours do not cover the slot.","override":null,"code_in_response":true},{"code":"outside_business_hours","when":"The staff member has no recorded hours and the slot is outside the business's opening hours.","override":null,"code_in_response":true},{"code":"time_off","when":"The staff member has time off overlapping the slot.","override":null,"code_in_response":true},{"code":"external_busy","when":"The staff member's connected calendar shows them busy during the slot.","override":null,"code_in_response":true},{"code":"clash","when":"The staff member already has an overlapping job or patient visit, buffers included.","override":null,"code_in_response":true},{"code":"daily_cap","when":"The staff member already has their daily job limit that day (default 6).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/assign","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.availability","description":"Open times to book on one day, judged by the rules appointment.book uses — service length and buffers (service_id), the staff member if named, skills, working hours, time off, other jobs, daily caps and busy time on connected calendars. With no staff on file, the business's recorded opening hours (hours_basis company_hours) — or, when none are recorded, weekday 9–5 and the summary says those are default hours. A clinic's patient visits block the provider's staff row. Times come back in the company's zone and, given the caller's timezone, as the time to SAY in their clock. Each slot names who would take it (staff), why in plain words (why: skill, who this contact saw last time, lightest day — never a guess) and best=true on the top-ranked one. Read-only. REST: GET /api/v1/schedule/availability.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"date":{"type":"string"},"duration_minutes":{"type":"integer","nullable":true,"description":"how long the job takes; omit for the staff default"},"skill":{"type":"string","nullable":true,"description":"the kind of work, matched against staff skills"},"timezone":{"type":"string","nullable":true,"description":"the caller's IANA zone if they said one, e.g. America/New_York"},"service_id":{"type":"integer","nullable":true},"staff_id":{"type":"integer","nullable":true},"contact_id":{"type":"integer","nullable":true,"description":"crm_contacts.id — the person they saw last time is preferred"},"location_id":{"type":"integer","nullable":true,"description":"the shop (locations.id) — its clock"},"max_slots":{"type":"integer","minimum":1,"maximum":500,"default":8,"description":"how many open times to return (8 = what a voice agent reads aloud; ask for more to see the whole day)"}},"required":["date"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/availability","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"caller_timezone":{},"date":{},"duration_minutes":{},"hours_basis":{},"slots":{},"status":{},"summary":{},"timezone":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment.book","description":"Book an appointment — the one create (REST: POST /api/v1/schedule/book). The time is read in the business's clock (a time with no zone is local; 'Z' is converted). Length: end_time, else duration_minutes, else the service's, else the staff default. Assigns whoever can take it — skill, working hours, time off, other jobs, daily cap — or checks the staff_id you name by the same rules. The customer is contact_id, customer_id, or customer_name/phone/email (a phone-only caller is fine). Mirrors to every connected calendar. If nobody can take it the slot is still booked and `unassigned_reason` says why; a clash, a past time or a named person who is off is refused in plain words. A business with no staff on file is held to its own opening hours (the hours availability shows); an owner or admin may pass override_hours=true to book outside them, and that is recorded. For a repeating appointment use appointment.book_series.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"start_time":{"type":"string","nullable":true},"service_id":{"type":"integer","nullable":true,"description":"the service booked; or give a title"},"title":{"type":"string","nullable":true,"description":"what the appointment is for; defaults to the service"},"contact_id":{"type":"integer","nullable":true,"description":"CRM contact attending"},"customer_id":{"type":"integer","nullable":true,"description":"customers.id attending (a different id from contact_id)"},"end_time":{"type":"string","format":"date-time","nullable":true,"description":"omit to use duration_minutes or the assignee's default"},"staff_id":{"type":"integer","nullable":true,"description":"who takes it; omit to assign whoever can"},"location":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"skill":{"type":"string","nullable":true,"description":"the kind of work, matched against the staff member's skills"},"duration_minutes":{"type":"integer","nullable":true,"description":"omit to use the assignee's default length"},"notify_customer":{"type":"boolean","default":true,"description":"email the customer their confirmation (false = the owner tells them)"},"customer_name":{"type":"string","nullable":true},"customer_phone":{"type":"string","nullable":true},"customer_email":{"type":"string","nullable":true},"location_id":{"type":"integer","nullable":true,"description":"the shop (locations.id)"},"override_hours":{"type":"boolean","default":false,"description":"owner/admin only: book outside the business's opening hours on purpose (recorded on the appointment)"},"confirmed_via":{"type":"string","nullable":true,"enum":["owner_call","owner_in_person","customer_reply_sms","customer_reply_email","customer_link","customer_voice","booked_by_customer","other"],"description":"the customer already agreed, and how (e.g. owner_call). Omit: booked live with the customer → confirmed; booked for the owner → scheduled"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["start_time"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"past_time","when":"start_time is in the past on the business's clock, beyond a short grace period.","override":null,"code_in_response":true},{"code":"class_full","when":"The service is a class and that time already has its capacity booked.","override":null,"code_in_response":true},{"code":"staff_inactive","when":"The named staff member (or the one running that class) is not active.","override":null,"code_in_response":true},{"code":"skill_mismatch","when":"A skill is given and the named staff member does not list it.","override":null,"code_in_response":true},{"code":"outside_hours","when":"The named staff member does not work that day, or their hours do not cover the slot.","override":null,"code_in_response":true},{"code":"outside_business_hours","when":"The slot is outside the business's opening hours (no staff at all, or the named staff member has no hours of their own). Owner/admin may pass override_hours.","override":"override_hours","code_in_response":true},{"code":"time_off","when":"The named staff member has time off overlapping the slot.","override":null,"code_in_response":true},{"code":"external_busy","when":"The connected calendar (the staff member's, or the owner's when there are no staff) shows busy.","override":null,"code_in_response":true},{"code":"clash","when":"The slot overlaps an open appointment for that staff member (or the business, with no staff), buffers included.","override":null,"code_in_response":true},{"code":"daily_cap","when":"The named staff member already has their daily job limit that day.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/book","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.book_series","description":"Book a REPEATING appointment (weekly cleaning, lessons every Tuesday, a monthly service). rrule is RFC 5545 without DTSTART (FREQ=WEEKLY;BYDAY=TU, FREQ=MONTHLY;BYDAY=2TU, FREQ=WEEKLY;INTERVAL=2); start_time is the FIRST visit and its clock time is every visit's time in the business's clock (daylight saving keeps the wall clock). End it with until or count, or leave it open. Every visit for the next 90 days is a real appointment booked by the same rules as appointment.book (a daily job books the days that come into range). A visit the regular person can't take is booked with nobody assigned; one nothing can take is skipped — both come back with the reason and the owner is told. Only the first visit refuses the whole request. REST: POST /api/v1/schedule/series.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"rrule":{"type":"string","description":"e.g. FREQ=WEEKLY;BYDAY=TU"},"start_time":{"type":"string","format":"date-time","description":"the first visit; no zone = business clock"},"end_time":{"type":"string","format":"date-time","nullable":true},"skill":{"type":"string","nullable":true},"customer_id":{"type":"integer","nullable":true},"customer_name":{"type":"string","nullable":true},"customer_phone":{"type":"string","nullable":true},"customer_email":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"location":{"type":"string","nullable":true,"description":"address text"},"location_id":{"type":"integer","nullable":true},"service_id":{"type":"integer","nullable":true},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440,"nullable":true},"staff_id":{"type":"integer","nullable":true,"description":"technicians.id — the regular person"},"contact_id":{"type":"integer","nullable":true,"description":"crm_contacts.id"},"until":{"type":"string","format":"date","nullable":true,"description":"last day (YYYY-MM-DD, the business's clock)"},"count":{"type":"integer","minimum":1,"nullable":true,"description":"how many visits in all"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["rrule","start_time"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"rrule_never_lands","when":"The recurrence rule produces no date within 5 years of the first visit.","override":null,"code_in_response":true},{"code":"nothing_to_book","when":"No visit could be booked in the next 90 days (a first visit already in the past is skipped, not refused).","override":null,"code_in_response":true},{"code":"class_full","when":"The FIRST visit is a full class; only the first visit can refuse the whole series.","override":null,"code_in_response":true},{"code":"outside_business_hours","when":"The FIRST visit is outside opening hours and cannot fall back to unassigned. Later visits are skipped or left unassigned, never refused.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/book-series","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.cancel","description":"Cancel an appointment. It stays on record as canceled with the reason, the reminders still to go to the customer are cleared, owner reminders tied to it are canceled, and connected calendars are updated. notify_customer true/false tells them or not; omitted, the sales motion decides (default: a card asking you). REST: POST /api/v1/schedule/{id}/cancel.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer (true) or not (false); omit → the sales motion's 'Tell them when it changes' step decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/cancel","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appointment_id":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment.cancel_request_mine","description":"Ask the business to cancel the caller's own appointment. A request — the business confirms it; never say it is canceled.","shape":"receipt","side_effects":"write","surfaces":["http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"cli":"not projected onto this surface; no reason recorded.","mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/cancel-request-mine","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.complete","description":"Done (→ completed). Fires any \"remind me when it's done\" reminders (reminder.set with on=appointment.complete). REST: POST /api/v1/schedule/{id}/complete.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/complete","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.confirm","description":"Mark an appointment confirmed (scheduled → confirmed) and record HOW: via owner_call ('Ray confirmed by phone'), owner_in_person, customer_reply_sms, customer_reply_email, customer_link, customer_voice, booked_by_customer or other. notify_customer=true also sends them a confirmation (default: no message). REST: POST /api/v1/schedule/{id}/confirm.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"notify_customer":{"type":"boolean","default":false},"via":{"type":"string","nullable":true,"enum":["owner_call","owner_in_person","customer_reply_sms","customer_reply_email","customer_link","customer_voice","booked_by_customer","other"]},"note":{"type":"string","nullable":true,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/confirm","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.confirm_mine","description":"Confirm the caller's own appointment (from appointment.mine). Anyone else's is refused.","shape":"receipt","side_effects":"write","surfaces":["http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_verified","when":"The caller's verified phone does not match the appointment's contact — answered the same as 'no booking'.","override":null,"code_in_response":true},{"code":"already_confirmed","when":"The appointment is already confirmed.","override":null,"code_in_response":true},{"code":"bad_transition","when":"The appointment is not in scheduled status.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"cli":"not projected onto this surface; no reason recorded.","mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/confirm-mine","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.en_route","description":"\"On my way\": marks the job en route and tells the customer (with eta_minutes if given). Only for work that travels to the customer — refused for a job at the business's own place. Texts go only when the business's SMS lane allows it (off until A2P registration); otherwise email, and the result says why. REST: POST /api/v1/schedule/{id}/en-route.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"eta_minutes":{"type":"integer","minimum":1,"nullable":true},"message":{"type":"string","nullable":true},"notify_customer":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_onsite","when":"The job does not travel to the customer (the service is not on-site, there is no address, or it is at one of the business's own locations).","override":null,"code_in_response":true},{"code":"already_en_route","when":"The appointment is already en route.","override":null,"code_in_response":true},{"code":"bad_transition","when":"The appointment is not scheduled or confirmed.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/en-route","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.get","description":"One appointment: when (in the business's clock), who, staff, service, status, cancel reason, reminders, who is responsible (the assigned person, or the owner by default until someone is assigned), what may be done next (allowed_actions) and its history (booked, moved, confirmed, …). Read-only. REST: GET /api/v1/schedule/{id}.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"kind":{"type":"string","enum":["appointment","healthcare"],"nullable":true,"description":"healthcare = a clinic visit from the list (id \"healthcare:<n>\")"}},"required":["appointment_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/get","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.list","description":"The calendar for a day or a range (start/end are YYYY-MM-DD on the business's clock, at most 62 days; omit start for the business's TODAY — never the UTC date): each day's appointments with status, customer, staff, service and allowed_actions, the open windows someone could still take, busy time from connected calendars (days[].external_events, e.g. busy at 2 on Google), the team, their time off, what nobody is assigned to yet, and `connections` (google/microsoft: connected, email, last_sync_at, status). `range.said` names the days and zone used. Filter by staff_id, contact_id or status. A clinic's patient visits are on it too (kind \"healthcare\", id \"healthcare:<n>\", no clinical detail, allowed_actions [] — changed in the healthcare module); a visit of a repeating appointment carries series {id, rule_text, occurrence_date}. Read-only. REST: GET /api/v1/schedule/agenda.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"start":{"type":"string","format":"date","nullable":true,"description":"first day, YYYY-MM-DD on the business's clock; omit for today"},"end":{"type":"string","format":"date","nullable":true,"description":"last day (inclusive); omit for one day"},"staff_id":{"type":"integer","nullable":true},"contact_id":{"type":"integer","nullable":true,"description":"crm_contacts.id"},"status":{"type":"string","nullable":true,"enum":["scheduled","confirmed","en_route","in_progress","completed","canceled","noshow"]}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/list","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.mark_no_show","description":"The customer didn't show (→ noshow). Clears the reminders still to go to them. REST: POST /api/v1/schedule/{id}/no-show.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/mark-no-show","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.mine","description":"The caller's own upcoming appointments (what, when, status), found by the number they are calling from. A number with no booking finds nothing — offer appointment.text_link instead. Read-only.","shape":"discovery","side_effects":"read","surfaces":["http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"cli":"not projected onto this surface; no reason recorded.","mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/mine","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.notify","description":"Tell the customer about their appointment: confirmation, reminder, en_route, running_late — or the review ask once it is done (sends the business's own review link; refused when none is set). Every messaging gate applies: SMS is off until A2P registration, so email is tried and the result lists which channel went and why the others did not. REST: POST /api/v1/schedule/{id}/notify.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"kind":{"type":"string","enum":["confirmation","reminder","en_route","running_late","review","rescheduled","canceled"]},"message":{"type":"string","nullable":true,"description":"your own words instead of the standard ones"},"eta_minutes":{"type":"integer","minimum":1,"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","kind"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"bad_transition","when":"The kind does not fit the status: review needs a completed job, canceled a canceled one, any other kind an open one.","override":null,"code_in_response":true},{"code":"no_review_link","when":"kind=review and the business has no approved review link.","override":null,"code_in_response":true},{"code":"not_sent","when":"The appointment has no customer contact; nothing is sent.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/notify","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.public_times","description":"What a customer is offered when booking on this business's website: whether the site books times or takes requests (and why), the services bookable online (public fields only), and for one service the next `days` days (which have open times) and the open times on `date` — or the first open day. Times are in the business's clock (`timezone`); no staff names. The same answer the website's booking block shows. Read-only. REST (public, by site host): GET /api/v1/cms/pages/public/booking/times. To book for someone, use appointment.book.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"service_id":{"type":"integer","nullable":true,"description":"service_catalog.id; omit for the first bookable service"},"date":{"type":"string","format":"date","nullable":true,"description":"YYYY-MM-DD in the business's clock; omit for the first open day"},"days":{"type":"integer","minimum":0,"maximum":31,"nullable":true,"description":"how many days the strip covers (default 14)"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/public-times","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.reschedule","description":"Move an appointment to a new time; without new_end_time it keeps its length. Its status is kept (the move is logged in its history), the same hours / time off / clash checks as a booking apply, customer reminders are re-timed and connected calendars are updated. A confirmed one needs confirming again when the business asks for confirmation. notify_customer: true = 'and let him know', false = 'don't tell him'; omitted, the sales motion decides (default: a card asking you). REST: POST /api/v1/schedule/{id}/reschedule.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"new_start_time":{"type":"string"},"new_end_time":{"type":"string","format":"date-time","nullable":true},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer (true) or not (false); omit → the sales motion's 'Tell them when it changes' step decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","new_start_time"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/reschedule","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appointment_id":{},"new_end_time":{},"new_start_time":{},"old_start_time":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment.reschedule_mine","description":"Move the caller's own appointment to a time appointment.availability offered; it is then confirmed and the business is told.","shape":"receipt","side_effects":"write","surfaces":["http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"new_start_time":{"type":"string","format":"date-time"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","new_start_time"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"cli":"not projected onto this surface; no reason recorded.","mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/reschedule-mine","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.series_end","description":"Stop a repeating appointment from from_date (default the business's today). Its visits from that day on are canceled with the reason unless keep_booked; earlier visits and the history stay. REST: POST /api/v1/schedule/series/{id}/end.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","minimum":1},"from_date":{"type":"string","format":"date","nullable":true},"reason":{"type":"string","nullable":true},"keep_booked":{"type":"boolean","default":false},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer — ONE message for every visit this touches; omit → the sales motion decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["series_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/series-end","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.series_get","description":"One repeating appointment: the rule in words (rule_text, e.g. \"Every Tuesday at 9 am\"), the template (who, what, where, length), its upcoming visits, how far ahead they are booked, and any visit that was skipped with the reason. Each appointment of a series carries series {id, rule_text, occurrence_date}. Read-only. REST: GET /api/v1/schedule/series/{id}.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","minimum":1}},"required":["series_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/series-get","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.series_update","description":"Change a repeating appointment. scope \"this\" (the default) changes one visit (appointment_id or occurrence_date) and marks it an exception; \"following\" splits the series at that visit (the old one ends the day before, a new one starts with the change); \"all\" changes the template and every future visit nobody changed on its own — moved, reassigned or edited, canceled where a new rule no longer lands, booked where it now does. start_time moves the time (and the weekday, when its date differs from the visit's). Every visit is re-checked by the booking rules; one that can't move keeps its time and is reported. REST: PATCH /api/v1/schedule/series/{id}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","minimum":1},"scope":{"type":"string","enum":["this","following","all"],"default":"this"},"appointment_id":{"type":"integer","nullable":true,"description":"the visit it applies from"},"occurrence_date":{"type":"string","format":"date","nullable":true},"start_time":{"type":"string","format":"date-time","nullable":true},"rrule":{"type":"string","nullable":true},"required_skill":{"type":"string","nullable":true},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer — ONE message for every visit this touches; omit → the sales motion decides"},"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"location":{"type":"string","nullable":true,"description":"address text"},"location_id":{"type":"integer","nullable":true},"service_id":{"type":"integer","nullable":true},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440,"nullable":true},"staff_id":{"type":"integer","nullable":true,"description":"technicians.id — the regular person"},"contact_id":{"type":"integer","nullable":true,"description":"crm_contacts.id"},"until":{"type":"string","format":"date","nullable":true,"description":"last day (YYYY-MM-DD, the business's clock)"},"count":{"type":"integer","minimum":1,"nullable":true,"description":"how many visits in all"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["series_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/series-update","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.start","description":"Started / checked in (→ in_progress). REST: POST /api/v1/schedule/{id}/start.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/start","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.text_link","description":"Send an appointment's own link (confirm / move / cancel) to the contact on file for it — never to the caller. Once a day per booking.","shape":"receipt","side_effects":"write","surfaces":["http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"cli":"not projected onto this surface; no reason recorded.","mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/text-link","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.unconfirm","description":"Undo a confirmation (confirmed → scheduled): 'undo that', 'he hasn't actually confirmed'. The only way back to scheduled; the customer is not told. A job that is not confirmed is refused (already_scheduled). REST: POST /api/v1/schedule/{id}/unconfirm.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_scheduled","when":"The appointment is not confirmed (already scheduled).","override":null,"code_in_response":true},{"code":"bad_transition","when":"The appointment is en route, in progress, completed, canceled or no-show.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/unconfirm","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.upcoming","description":"List upcoming appointments for this company in the next N days (default 7), from now, on the business's own clock. Excludes canceled and no-show. The SAME read as appointment_list (each row is the full appointment: customer, staff, series, allowed_actions; a clinic's patient visits too) plus the old keys (appointment_id, staff_id). Read-only. Use when the user asks 'what's on the calendar' or 'who's coming in this week'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":30,"description":"Default 7."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."}}},"required_scope":null,"transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/upcoming","http_method":"POST","dispatch_endpoint":null},{"name":"appointment.update","description":"Edit an appointment's details: title, notes, address (location), location_id, service_id (a new service resets the length to the service's unless duration_minutes is given), duration_minutes (moves the end — the same clash, hours, time-off and outside-calendar checks as a booking), contact_id (the customer, crm_contacts.id) and required_skill. NOT the start time (use appointment.reschedule) or the staff member (appointment.assign). Every change is kept in its history. REST: PATCH /api/v1/schedule/{id}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"location":{"type":"string","nullable":true,"description":"address text"},"location_id":{"type":"integer","nullable":true},"service_id":{"type":"integer","nullable":true},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440,"nullable":true},"contact_id":{"type":"integer","nullable":true,"description":"crm_contacts.id"},"required_skill":{"type":"string","nullable":true},"notify_customer":{"type":"boolean","nullable":true,"description":"tell the customer (true) or not (false); omit → the sales motion decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"35","noun":"appointment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/appointment/update","http_method":"POST","dispatch_endpoint":null},{"name":"appointment_assign","description":"Give an appointment to another staff member ('give Kim's water heater to Rosa'), optionally at a new start_time. The same skill, hours, time-off and clash checks as a booking.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"staff_id":{"type":"integer","description":"technicians.id"},"start_time":{"type":"string","description":"optional ISO 8601 new start"},"notify_customer":{"type":"boolean","description":"with a new time: 'let him know' → true, 'don't tell him' → false; omit → the business's setting decides"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","staff_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.assign","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_availability","description":"Open times on one day ('who's free Tuesday morning'), by the rules a booking is judged by: service length and buffers, staff hours, time off, other jobs, daily caps. date is YYYY-MM-DD in the business's clock. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"date":{"type":"string","description":"YYYY-MM-DD"},"duration_minutes":{"type":"integer"},"service_id":{"type":"integer"},"staff_id":{"type":"integer"},"skill":{"type":"string"},"contact_id":{"type":"integer","description":"crm_contacts.id — who they saw last time counts"}},"required":["date"]},"required_scope":null,"transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.availability","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_book","description":"Book an appointment on the company's calendar. Times are ISO 8601 — timezone-aware strings are converted, naive ones are the company's local time. Title is required (what the appointment is for). Who: contact_id (a CRM contact), customer_id, or a new person's name/phone/email. Length: end_time, duration_minutes, the service's, or the staff default. A clash, a past time, or a named staff member who is off is refused in plain words. Use this when the user says 'schedule a meeting' or 'book Jane for Tuesday at 2'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"What the appointment is for. 3–255 chars.","minLength":3,"maxLength":255},"start_time":{"type":"string","description":"ISO 8601 start time (e.g. 2026-06-15T14:30:00-06:00)."},"end_time":{"type":"string","description":"ISO 8601 end time. Omit to use the service's or staff member's length."},"service_id":{"type":"integer","description":"Optional service booked (length, buffers)."},"duration_minutes":{"type":"integer","description":"Optional length when there is no end_time."},"skill":{"type":"string","description":"Optional kind of work, matched to staff skills."},"customer_name":{"type":"string","description":"A new person's name (no contact yet)."},"customer_phone":{"type":"string","description":"A new person's phone — enough on its own."},"customer_email":{"type":"string","description":"A new person's email."},"customer_id":{"type":"integer","description":"Optional customers.id of the attendee."},"contact_id":{"type":"integer","description":"Optional CRM contact id (crm_contacts.id) of the attendee, used when customer_id is not given. Their customer record is found — or created when the booking is confirmed, never at preview."},"staff_id":{"type":"integer","description":"Optional staff member (technicians.id). Omit to assign whoever can take it."},"location":{"type":"string","description":"Optional physical or virtual meeting location.","maxLength":255},"description":{"type":"string","description":"Optional longer description.","maxLength":2000},"override_hours":{"type":"boolean","description":"Owner/admin only, and only when the owner says so: book outside the business's opening hours on purpose. Recorded on the appointment."},"confirmed_via":{"type":"string","enum":["owner_call","owner_in_person","customer_reply_sms","customer_reply_email","customer_link","customer_voice","other"],"description":"Only when the owner says the customer ALREADY agreed, and how ('they already said yes on the phone' → owner_call). Omit it and a booking you make for the owner is scheduled, not confirmed."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","start_time"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.book","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"appointment_id":{},"assigned_to":{},"calendars":{},"company_id":{},"customer_id":{},"end_time":{},"ok":{},"preflight":{},"staff_id":{},"start_time":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment_book_series","description":"Book a REPEATING appointment ('weekly cleaning every Friday at 10', 'lessons every Tuesday at 4', 'monthly service on the 2nd Monday'). rrule is RFC 5545: FREQ=WEEKLY;BYDAY=FR · FREQ=WEEKLY;INTERVAL=2;BYDAY=MO · FREQ=MONTHLY;BYDAY=2MO · FREQ=MONTHLY;BYMONTHDAY=15. start_time is the FIRST visit (its clock time is every visit's time in the business's clock). Stop it with until (a date) or count, or leave it open. Visits are booked 90 days ahead by the same rules as a single booking; a visit the regular person can't take is booked with nobody assigned, one nothing can take is skipped — the result lists both with the reason, and the owner is told.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"rrule":{"type":"string","description":"e.g. FREQ=WEEKLY;BYDAY=TU"},"start_time":{"type":"string","description":"ISO 8601 — the first visit"},"end_time":{"type":"string","description":"optional ISO end of the first visit"},"skill":{"type":"string"},"customer_name":{"type":"string"},"customer_phone":{"type":"string"},"customer_email":{"type":"string"},"title":{"type":"string"},"notes":{"type":"string"},"location":{"type":"string","description":"address text"},"location_id":{"type":"integer"},"service_id":{"type":"integer"},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440},"staff_id":{"type":"integer","description":"technicians.id — the regular person"},"contact_id":{"type":"integer","description":"crm_contacts.id"},"until":{"type":"string","description":"last day, YYYY-MM-DD"},"count":{"type":"integer","minimum":1,"description":"how many visits in all"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["rrule","start_time"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.book_series","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_cancel","description":"Cancel an appointment. Status becomes 'canceled' and the reason is kept. The row is preserved (not deleted) for the record; the customer's pending reminders are cleared.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id to cancel."},"reason":{"type":"string","description":"Optional cancellation reason (kept on the appointment).","maxLength":500},"notify_customer":{"type":"boolean","description":"'and let him know' → true; 'don't tell him' → false. Omit when the owner said neither — the business's own setting decides (by default you'll be asked on a card)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.cancel","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"appointment_id":{},"ok":{},"preflight":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment_complete","description":"'Done at Nina's': the job is completed. Fires any 'remind me when it's done' reminders.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.complete","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_confirm","description":"Mark an appointment confirmed and say HOW: 'Ray confirmed by phone' → via owner_call; 'he said yes in person' → owner_in_person. No message goes to the customer unless notify_customer is true. 'Who hasn't confirmed?' is appointment_list status=scheduled (and confirmation_required says whether this business asks at all).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"notify_customer":{"type":"boolean"},"via":{"type":"string","enum":["owner_call","owner_in_person","customer_reply_sms","customer_reply_email","customer_link","customer_voice","booked_by_customer","other"]},"note":{"type":"string","maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.confirm","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_en_route","description":"'Tell Carl I'm on my way': marks the job en route and tells the customer (eta_minutes optional). Only for work that travels to the customer. Texts go only when the business's SMS lane allows (off until A2P); otherwise email, and the result says why.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"eta_minutes":{"type":"integer"},"message":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.en_route","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_get","description":"One appointment in full — when, who, staff, status, reminders, what can be done next, and its history. `responsible` says who has it: the assigned person, or — when by_default is true — the owner until someone is assigned (say 'You, until you assign someone' to that person). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"}},"required":["appointment_id"]},"required_scope":null,"transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_list","description":"The calendar for a day or a range: 'what's coming up', 'anything tomorrow', 'Jake's week', 'am I free at 2?'. start/end are YYYY-MM-DD on the business's clock (omit start for TODAY on that clock — never compute it from UTC; end optional, max 62 days). Returns each day's appointments (status, customer, staff, what can be done next), open windows, the team, time off, unassigned jobs, busy time from connected calendars (days[].external_events: 'you're busy at 2 on Google') and `connections` (Google/Microsoft: connected as, last sync). `range.said` names the days and zone used — repeat it. Each appointment's `responsible` is who has it (by_default=true: the owner until someone is assigned). 'Who hasn't confirmed?' → status=scheduled over the coming days; when `confirmation_required` is false this business doesn't ask customers to confirm, so say nobody is waiting on it rather than listing them as a problem. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"start":{"type":"string","description":"YYYY-MM-DD on the business's clock; omit for today"},"end":{"type":"string","description":"YYYY-MM-DD, inclusive; omit for one day"},"staff_id":{"type":"integer"},"contact_id":{"type":"integer","description":"crm_contacts.id"},"status":{"type":"string","enum":["scheduled","confirmed","en_route","in_progress","completed","canceled","noshow"]}}},"required_scope":null,"transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_mark_no_show","description":"'Carl didn't show': marks the appointment a no-show and clears the reminders still to go to them.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.mark_no_show","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_notify","description":"Tell the customer about their appointment — kind: confirmation, reminder, en_route, running_late, or review (after the job is done; sends the business's own review link). 'Text Deborah we're running late.' SMS is off until A2P registration, so email is tried; the result says which channel went and why the others did not.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"kind":{"type":"string","enum":["confirmation","reminder","en_route","running_late","review","rescheduled","canceled"]},"message":{"type":"string","description":"your own words instead of the standard ones"},"eta_minutes":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","kind"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.notify","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_reschedule","description":"Move an existing appointment to a new time. Only scheduled or confirmed work moves. Its status is KEPT (the move is logged in its history); without new_end_time it keeps its length. The same hours / time-off / clash checks as a booking apply.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id to reschedule."},"new_start_time":{"type":"string","description":"ISO 8601 new start time."},"new_end_time":{"type":"string","description":"ISO 8601 new end time. Omit to keep the length."},"notify_customer":{"type":"boolean","description":"'and let him know' → true; 'don't tell him' → false. Omit when the owner said neither — the business's own setting decides (by default you'll be asked on a card)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id","new_start_time"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.reschedule","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"appointment_id":{},"new_end_time":{},"new_start_time":{},"ok":{},"preflight":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"appointment_series_end","description":"Stop a repeating appointment ('stop Mia's lessons after June'): from_date (default today) on, its visits are canceled with the reason unless keep_booked. Earlier visits and the history stay.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","description":"appointment_series.id"},"from_date":{"type":"string","description":"YYYY-MM-DD, the first day with no visit"},"reason":{"type":"string"},"keep_booked":{"type":"boolean"},"notify_customer":{"type":"boolean","description":"'let him know' → true, 'don't tell him' → false; omit → the business's setting decides. One message covers every visit changed."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["series_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.series_end","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_series_get","description":"One repeating appointment: how it repeats in words, who / what / where, its upcoming visits and any visit that was skipped and why. An appointment's series.id (appointment_get / appointment_list) is the series_id. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","description":"appointment_series.id"}},"required":["series_id"]},"required_scope":null,"transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.series_get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_series_update","description":"Change a repeating appointment. ALWAYS ask which: 'just this one' (scope this — the default; one visit, the rest unchanged), 'this and the ones after' (scope following — from that visit on) or 'all of them' (scope all — every upcoming visit nobody changed on its own). Name the visit with appointment_id or occurrence_date. start_time moves the time (and the weekday if the date differs). Every moved visit is re-checked by the booking rules; one that can't move keeps its time and is reported.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"series_id":{"type":"integer","description":"appointment_series.id"},"scope":{"type":"string","enum":["this","following","all"]},"appointment_id":{"type":"integer","description":"the visit (appointments.id)"},"occurrence_date":{"type":"string","description":"the visit's date, YYYY-MM-DD"},"start_time":{"type":"string","description":"ISO 8601 new time for the visit(s)"},"rrule":{"type":"string","description":"a new repeat rule (following / all)"},"required_skill":{"type":"string"},"notify_customer":{"type":"boolean","description":"'let him know' → true, 'don't tell him' → false; omit → the business's setting decides. One message covers every visit changed."},"title":{"type":"string"},"notes":{"type":"string"},"location":{"type":"string","description":"address text"},"location_id":{"type":"integer"},"service_id":{"type":"integer"},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440},"staff_id":{"type":"integer","description":"technicians.id — the regular person"},"contact_id":{"type":"integer","description":"crm_contacts.id"},"until":{"type":"string","description":"last day, YYYY-MM-DD"},"count":{"type":"integer","minimum":1,"description":"how many visits in all"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["series_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.series_update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_start","description":"'Starting at Nina's': the job is under way (in_progress).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.start","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_unconfirm","description":"Undo a confirmation — 'undo that', 'he hasn't actually confirmed': confirmed → scheduled. The customer is not told.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"reason":{"type":"string","maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.unconfirm","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"appointment_update","description":"Edit an appointment's details ('change Ray's notes', 'make it 90 minutes', 'the address is 12 Elm St', 'it's for Dana, not Ray'): title, notes, location (address), location_id, service_id, duration_minutes (same checks as a booking), contact_id, required_skill. Not the time (appointment_reschedule) or the person (appointment_assign).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"appointments.id"},"title":{"type":"string"},"notes":{"type":"string"},"location":{"type":"string","description":"address text"},"location_id":{"type":"integer"},"service_id":{"type":"integer"},"duration_minutes":{"type":"integer","minimum":1,"maximum":1440},"contact_id":{"type":"integer","description":"crm_contacts.id"},"required_skill":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"35","noun":"appointment","location":"svc.api","same_as":"appointment.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"asset.archive","description":"Take a stored asset out of the media library, recoverably. Status becomes 'deleted', deleted_at is stamped and the asset leaves asset.list and asset.stats — but the database row AND the stored file both survive, and THE PUBLIC URL KEEPS WORKING, so a live page that still renders it is not broken. asset.restore undoes it exactly. Known references are returned for information, never as a refusal. Use asset.delete only to destroy the file.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["asset_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":"asset.restore","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/archive","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"already_archived":{},"archived":{},"asset_id":{},"detail":{},"known_usages":{},"public_url_still_served":{},"recoverable":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"asset.delete","description":"PERMANENTLY delete a stored asset: the object in the bucket AND the database row. No undo, no rollback window, and its public URL stops working — any page still using it goes blank. To take an asset out of the library recoverably (URL still served), use asset.archive instead. Refused, with the pages named, when the asset is still referenced; fails closed when that check cannot run. An empty usage result is reported as 'not_indexed', never as proof the asset is unused. Legacy: an explicit hard_delete=false is honoured as asset.archive.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1},"hard_delete":{"type":"boolean","description":"Legacy. Omit (permanent). false = asset.archive."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["asset_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"asset_in_use","when":"Something still references the asset (e.g. a page); the response names the usages. hard_delete=false archives instead and is never refused.","override":null,"code_in_response":true},{"code":"usage_check_unavailable","when":"The usage lookup failed; the delete fails closed and nothing is removed.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"asset_id":{},"detail":{},"error":{},"status":{},"usages":{},"used_by_count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"asset.generate","description":"Make an image or a video from a prompt and keep it in this tenant's own asset library. Call asset.quote first if you want the price. With no provider_key the cheapest priceable option is used, so an unspecified call cannot land on the most expensive model. The result is stored as a real asset with its prompt recorded — the provider's own links expire (Higgsfield keeps results 7 days), so use the returned asset id anywhere a page wants an image. A provider whose price needs an account-specific estimate refuses BEFORE generating. Pricing a resolution happens after generation, so quote first (asset.quote) when the resolution matters.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"description":"What to make. This is recorded on the asset."},"kind":{"type":"string","enum":["image","video"],"default":"image"},"provider_key":{"type":"string","nullable":true},"resolution":{"type":"string","nullable":true},"num_items":{"type":"integer","minimum":1,"default":1},"duration_sec":{"type":"number","nullable":true},"category":{"type":"string","nullable":true,"description":"Media-library category for the stored asset (branding, marketing, products, documents, general)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prompt"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_generator_configured","when":"Nothing configured can generate that kind (image or video) right now.","override":null,"code_in_response":false},{"code":"provider_cannot_generate_kind","when":"The given provider_key cannot generate that kind; the response lists options.","override":null,"code_in_response":false},{"code":"no_priceable_provider","when":"No provider_key given and no provider can be priced for that kind and resolution.","override":null,"code_in_response":false},{"code":"provider_unpriceable","when":"The provider's price needs an account-specific estimate; refused before generating, nothing billed.","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/generate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"asset_ids":{},"assets":{},"billed":{},"cost":{},"error":{},"generated":{},"key_scope":{},"kind":{},"note":{},"ok":{},"options":{},"preview_urls":{},"prompt":{},"provider_key":{},"quotes":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"asset.get","description":"One stored asset's full record by its ast_... id: filename, mime, size, width/height, category, owner, storage URL, status, the WebP renditions under extra.variants, and its provenance block (who generated it, under what prompt and licence — NULL there means UNKNOWN, never cleared). Answers for soft-deleted assets too, with status 'deleted', which is how an agent confirms a delete it just made. An asset belonging to another tenant returns asset_not_found — the same answer as one that never existed.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1}},"required":["asset_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/get","http_method":"POST","dispatch_endpoint":null},{"name":"asset.list","description":"Everything this tenant has in its asset store, newest first: id, filename, mime, size, dimensions, category and the public URL for each. Filter by category (branding, products, agents, documents, general) or by owner_id ('agent:maya', 'user:123'), and page with limit/offset — `total` is the whole count, `count` is this page. Ready assets only: soft-deleted and still-pending uploads are not listed (use asset.get for a deleted one). This is how an agent finds an image it stored earlier instead of generating it again.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","nullable":true},"owner_id":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":500,"default":100},"offset":{"type":"integer","minimum":0,"default":0}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/list","http_method":"POST","dispatch_endpoint":null},{"name":"asset.quote","description":"What an image or video would cost before you make one. Returns every provider that can generate it, with your price per item and the cheapest option. Costs nothing and generates nothing. A provider that prices per account rather than publishing a rate is reported as not priceable with the reason — we refuse to guess a wholesale figure, because it gets multiplied by the markup and billed. Prices shown are what you pay us; a generation on your own connected key is billed by that provider directly and does not appear here.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["image","video"],"default":"image"},"provider_key":{"type":"string","nullable":true,"description":"Price just this one, e.g. openai_dalle3"},"resolution":{"type":"string","nullable":true},"num_items":{"type":"integer","minimum":1,"default":1},"duration_sec":{"type":"number","nullable":true,"description":"Video only — seconds"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_generator_configured","when":"Nothing configured can generate that kind.","override":null,"code_in_response":false},{"code":"provider_cannot_generate_kind","when":"The given provider_key cannot generate that kind; the response lists options.","override":null,"code_in_response":false}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/quote","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cheapest":{},"error":{},"kind":{},"note":{},"num_items":{},"ok":{},"options":{},"quotes":{},"resolution":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"asset.restore","description":"Undo asset.archive: the asset returns to status 'ready' and reappears in asset.list. Idempotent on an asset that is not archived. A permanently deleted asset (asset.delete) has no row left and answers asset_not_found.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["asset_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":"asset.archive","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/restore","http_method":"POST","dispatch_endpoint":null},{"name":"asset.stats","description":"How much storage this tenant is using: total asset count, total bytes and MB, and a per-category breakdown (count + bytes). Counts READY assets only, so a soft-deleted asset stops counting against the tenant immediately even though its bytes are still in the bucket. Call this before a bulk generation run, or to answer 'how big is our media library'.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/stats","http_method":"POST","dispatch_endpoint":null},{"name":"asset.upload","description":"Upload a file and get back a public URL a page can point at. Send the bytes as base64 in content_base64 (a data: URI is accepted). Takes image/*, video/*, audio/*, PDF and SVG — video and audio included, so a page that moves has somewhere to host its media — plus Lottie animations: application/json (or a .json filename) is accepted ONLY when it parses as a Lottie document (top-level v, fr, ip, op, w, h, layers), up to 5 MB, and is stored as application/json; any other JSON is refused. Stores into this tenant's own asset bucket and returns url + asset_id; WebP renditions are generated for images. Unlike storage.upload and file.upload, this one actually carries the file.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"filename":{"type":"string"},"content_base64":{"type":"string"},"content_type":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"alt_text":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content_base64","filename"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"unsupported_media_type","when":"The file is not image, video, audio, font, PDF, SVG, Rive or Lottie; the response says where it belongs.","override":null,"code_in_response":true},{"code":"lottie_too_large","when":"A JSON (Lottie) upload is over 5 MB.","override":null,"code_in_response":true},{"code":"invalid_json","when":"A JSON upload is not valid UTF-8 JSON.","override":null,"code_in_response":true},{"code":"not_a_lottie_animation","when":"A JSON upload lacks Lottie's top-level keys (v, fr, ip, op, w, h, layers).","override":null,"code_in_response":true},{"code":"file_too_large","when":"The decoded file is over 25 MB.","override":null,"code_in_response":true},{"code":"executable_content","when":"The bytes are an executable.","override":null,"code_in_response":true},{"code":"archive_not_media","when":"The bytes are a zip archive (a website folder imports with nest.import).","override":null,"code_in_response":true},{"code":"content_does_not_match_type","when":"The bytes are not the media type they are labelled.","override":null,"code_in_response":true},{"code":"unsafe_svg","when":"The SVG embeds a DTD or entities.","override":null,"code_in_response":true},{"code":"invalid_svg","when":"The SVG does not parse.","override":null,"code_in_response":true},{"code":"pdf_active_content","when":"The PDF contains JavaScript or a launch action.","override":null,"code_in_response":true},{"code":"malware_detected","when":"The virus scan matched a signature.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/upload","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"mime":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"asset.url","description":"Just the public URL for one stored asset, returned as both `url` (the key asset.upload hands back) and `cdn_url`. asset.get returns this too along with everything else; this exists because the common case — an agent that stored a file, lost the URL, and wants to put it on a page block — should not have to read a whole record to find one string.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1}},"required":["asset_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/url","http_method":"POST","dispatch_endpoint":null},{"name":"asset.usage","description":"Where a stored asset actually appears. Returns every page that references it with the exact field — 'layout_json.sections[2].imageUrl' — plus the page's title and slug, so a delete can be judged before it is made. Read this before asset.delete. An empty list means NO KNOWN reference, not proof the asset is unused: a page holding an external or unrecognised URL shape is deliberately not recorded, because a false link would block a delete for a reason nobody could find. Draft layouts count — an asset used only in an unpublished draft is still in use, and deleting it blanks the page one publish later.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"asset_id":{"type":"string","minLength":1}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"89","noun":"asset","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/asset/usage","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"asset_id":{},"count":{},"error":{},"note":{},"referenced":{},"status":{},"usages":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit.anchors","description":"Published chain heads for this company, newest first. Each day the platform takes the newest hash of this tenant's attested action ledger and places it with an independent timestamp authority, so a later rewrite of the ledger would contradict a record we cannot reach. Returns the day, the head hash, how many rows the chain held, and status: 'anchored' means a third party holds a signed statement that this hash existed on that date; 'pending' means it was recorded but is still only in our own database and proves nothing on its own; 'failed' means we tried and could not, with the reason. `timestamped_digest` is what an auditor recomputes to check the token.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":365,"default":30}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/anchors","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"anchored":{},"anchors":{},"count":{},"not_anchored":{},"note":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit.explain_balance_change","description":"Causal chain for a commission-ledger balance change.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"ledger_entry_id":{"type":"integer","minimum":1}},"required":["ledger_entry_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"564","noun":"commission_ledger","acts_on":{"noun":"commission_ledger","address":"564","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/explain-balance-change","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"entry":{},"error":{},"error_code":{},"factors":{},"history":{},"narrative":{},"running_balance":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit.export","description":"Page through this tenant's audit_logs newest-first, filtered by optional since/until, resource_type and action. Returns rows, a count, and next_cursor to pass as cursor_after_id for the next page.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string","format":"date-time","nullable":true},"until":{"type":"string","format":"date-time","nullable":true},"resource_type":{"type":"string","nullable":true},"action":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":500,"default":100},"cursor_after_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/export","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"max":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit.log_list","description":"List recent AIAuditLog rows for this company. Use to investigate a recent action, see denied attempts, or audit ADA's own behavior. Returns most recent first.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200},"since_hours":{"type":"integer","description":"Only include rows from the last N hours.","minimum":1,"maximum":720}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/log-list","http_method":"POST","dispatch_endpoint":null},{"name":"audit.log_search","description":"Search the audit log by action_type / status / agent_type / time window. Use for compliance investigation, dispute defense, or seeing every attempt at a particular verb.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"action_type":{"type":"string"},"status":{"type":"string","enum":["pending","executed","denied","failed","initiated"]},"agent_type":{"type":"string"},"since_hours":{"type":"integer","minimum":1,"maximum":720},"limit":{"type":"integer","minimum":1,"maximum":500}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/log-search","http_method":"POST","dispatch_endpoint":null},{"name":"audit.receipts","description":"What verbs actually ran for this company: one receipt per call on every surface (CLI, HTTP, MCP, WebMCP, ADA, agents, voice) — verb, outcome (success / fail / refused / preview), reason, who (actor), surface, a fingerprint of the arguments (never their values), duration. Newest first. correlation_id links a preview card to its confirmation; session_ref returns every verb of ONE run (one phone call, one console session, one CLI invocation) so a journey can be read back in order. Each row's evidence_ref points at the durable proof behind the call — usually substrate:<id>, the attested decision row.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"verb":{"type":"string","nullable":true},"outcome":{"type":"string","enum":["success","fail","refused","preview"],"nullable":true},"surface":{"type":"string","nullable":true},"actor_id":{"type":"string","nullable":true},"correlation_id":{"type":"string","nullable":true},"session_ref":{"type":"string","nullable":true},"since":{"type":"string","format":"date-time","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":500,"default":50},"cursor_before_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/receipts","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"next_cursor_before_id":{},"receipts":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit.revert","description":"Revert a single ADA action by its AIAuditLog id. Before-state is read from the entity_versions snapshot written at action time (AIAuditLog itself still stores only an arguments_hash — that is deliberate). Reverts only where exactly one version matches the action. Two refusals, and they mean different things: `before_state_not_recorded` (no version row — the entity type is not versioned, or the action wrote nothing) and `ambiguous_before_state` (several rows match; which to restore is unknowable, and restoring the wrong record is worse than restoring none). Both change NOTHING. Only whitelisted action types are attempted at all.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"audit_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["audit_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"audit","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_reverted","when":"The action was already reverted.","override":null,"code_in_response":true},{"code":"cannot_unsend_voice_call","when":"The action was an outbound call — it cannot be undone.","override":null,"code_in_response":true},{"code":"cannot_unsend_sms","when":"The action was a sent text — it cannot be undone.","override":null,"code_in_response":true},{"code":"cannot_unsend_email","when":"The action was a sent email — it cannot be undone.","override":null,"code_in_response":true},{"code":"use_refund_not_revert","when":"The action was a charge or capture — refund it instead.","override":null,"code_in_response":true},{"code":"deletion_permanent_use_backup_restore","when":"The action deleted a contact or deal — restore from backup instead.","override":null,"code_in_response":true},{"code":"unsupported_action_type","when":"Only deals_advance, contact_update, crm_contacts_update, task_complete and crm_tasks_complete can be reverted.","override":null,"code_in_response":true},{"code":"before_state_not_recorded","when":"No recorded before-state matches the action; nothing changes.","override":null,"code_in_response":true},{"code":"ambiguous_before_state","when":"Two or more recorded before-states match, so which to restore is unknowable.","override":null,"code_in_response":true},{"code":"concurrent_modification","when":"Every field has changed since the action; fields changed by someone else are skipped, the rest reverted.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/audit/revert","http_method":"POST","dispatch_endpoint":null},{"name":"audit_log_list","description":"List recent AIAuditLog rows for this company. Use to investigate a recent action, see denied attempts, or audit ADA's own behavior. Returns most recent first.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200},"since_hours":{"type":"integer","description":"Only include rows from the last N hours.","minimum":1,"maximum":720}}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"audit","location":"svc.api","same_as":"audit.log_list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"entries":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"audit_log_search","description":"Search the audit log by action_type / status / agent_type / time window. Use for compliance investigation, dispute defense, or seeing every attempt at a particular verb.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"action_type":{"type":"string"},"status":{"type":"string","enum":["pending","executed","denied","failed","initiated"]},"agent_type":{"type":"string"},"since_hours":{"type":"integer","minimum":1,"maximum":720},"limit":{"type":"integer","minimum":1,"maximum":500}}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"audit","location":"svc.api","same_as":"audit.log_search","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"entries":{},"filters":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"backup.create","description":"Trigger a tenant data backup (export to compressed file). Long-running — enqueues a Celery task and returns the task id. Owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"format":{"type":"string","enum":["json","sql"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"backup","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/backup/create","http_method":"POST","dispatch_endpoint":null},{"name":"backup_create","description":"Trigger a tenant data backup (export to compressed file). Long-running — enqueues a Celery task and returns the task id. Owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"format":{"type":"string","enum":["json","sql"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"backup","location":"svc.api","same_as":"backup.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"celery_task_id":{},"format":{},"preflight":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"bids.create_intake","description":"Bids — start a bid or estimate from what the job IS: 0–10 photos (base64, or {content_base64, filename, content_type}; JPEG/PNG/WebP/HEIC, 10 MB each; walk & shoot: photo_marks = ms into the narration each was taken, photo_captions = the words said taking each), a spoken walkthrough (narration: one audio clip the same way, ≤25 MB), and/or words (customer_message). At least one. document_type names the draft (estimate, bid, quote, or plan — a clinic's treatment plan; default bid). Files are stored in company storage; the analysis transcribes and prices from the company's catalog and writes a draft proposal. Same intake as POST /api/v1/bids/intake/app. Then: bids.get_intake until ready.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"photos":{"type":"array","maxItems":10,"items":{"type":["string","object"]}},"photo_marks":{"nullable":true,"type":"array","maxItems":10,"items":{"type":["integer","null"]},"description":"walk & shoot: one per photo — ms into the narration when it was taken"},"photo_captions":{"nullable":true,"type":"array","maxItems":10,"items":{"type":["string","null"]},"description":"walk & shoot: one per photo — the words said taking it"},"narration":{"nullable":true,"type":["string","object"],"description":"one audio clip — base64 or {content_base64, filename, content_type}"},"contact_id":{"nullable":true,"type":"integer","description":"this company's CRM contact the bid is for"},"customer_message":{"nullable":true,"type":"string","description":"what the job needs, in words — typed or dictated"},"document_type":{"nullable":true,"type":"string","enum":["estimate","bid","quote","plan"]},"target_proposal_id":{"nullable":true,"type":"integer","description":"add the drafted lines to this open document (proposals.get) instead of starting one"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/create-intake","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"intake_id":{},"media_count":{},"next":{},"pipeline_status":{},"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"bids.finalize_intake","description":"Bids — approve a ready intake's AI-drafted proposal (company-scoped). Never emails the customer; send the priced bid from the proposals UI. Passing `amount` raises — finalizing approves a price, it does not set one. `proposal_id` closes a draft the AI could not write (status failed) with the document the owner built by hand from it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"amount":{"nullable":true,"type":"number","description":"Not supported — raises. Edit the proposal to change the amount."},"proposal_id":{"nullable":true,"type":"integer","description":"this company's document built by hand for a failed draft (proposals.get)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["intake_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/finalize-intake","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"intake_id":{},"intake_status":{},"sent_to_customer":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"bids.get_intake","description":"Bids — one intake: where its draft is (pending, analyzing, ready, failed, finalized, rejected), what the analysis flagged (warnings, and per line: items[].check with the reason), the customer's phone and email, recording_url (the call it came from; null otherwise), and the draft's proposal_id once written — read it with proposals.get. Company-scoped. Same row as GET /api/v1/bids/intakes/{id}.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1}},"required":["intake_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/get-intake","http_method":"POST","dispatch_endpoint":null},{"name":"bids.list_intakes","description":"Bids — the AI-drafts inbox: every intake newest first, grouped by what the owner has to do — needs_you (ready), didnt_work (failed), working (pending/analyzing), done (finalized/rejected). Each row has its group, who it is for, the AI's total, why it failed in plain words, and warnings_count (the checks to look at). Company-scoped. Same rows as GET /api/v1/bids/intakes.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"statuses":{"nullable":true,"type":"array","items":{"type":"string","enum":["pending","analyzing","ready","failed","finalized","rejected"]}},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/list-intakes","http_method":"POST","dispatch_endpoint":null},{"name":"bids.reanalyze_intake","description":"Bids — write an intake's draft again (after a failure, or for another pass). Replaces the previous draft; a finalized intake is closed — start a new one. Same as POST /api/v1/bids/intakes/{id}/reanalyze.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["intake_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/reanalyze-intake","http_method":"POST","dispatch_endpoint":null},{"name":"bids.reject_intake","description":"Bids — discard an intake and stop its follow-ups (company-scoped).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"reason":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["intake_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"361","noun":"estimate_draft","acts_on":{"noun":"estimate_draft","address":"361","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/bids/reject-intake","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"intake_id":{},"intake_status":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"bill_mark_paid","description":"Record that a bill (accounts payable) was paid — when, how, and the check or confirmation number. Records the fact only; it does not pay anyone.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"paid_at":{"type":"string","description":"YYYY-MM-DD; default today."},"payment_method":{"type":"string","enum":["card","cash","check","ach","company_card","personal_reimburse","other"]},"reference":{"type":"string","description":"Check or confirmation number."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"expense.mark_paid","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount":{},"preview":{},"purchase_id":{},"vendor":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"billing.add_payment_method","description":"Billing — put a card on file. NOT EXECUTABLE from an agent surface; always raises. The Stripe payment-method token is created client-side by the cardholder — use POST /api/v1/billing/payment-method/add.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"payment_method_id":{"type":"string"},"set_default":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["payment_method_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"583","noun":"platform_payment_method","acts_on":{"noun":"platform_payment_method","address":"583","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/billing/add-payment-method","http_method":"POST","dispatch_endpoint":null},{"name":"billing.checkout_link","description":"Billing — create a Solid# subscription checkout link. NOT IMPLEMENTED; always raises. Solid# checkout is priced per tier, not per arbitrary amount. To collect money from your own customers use create_payment_link.","shape":"aggregate","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount":{"type":"number"},"description":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount","description"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"583","noun":"platform_payment_method","acts_on":{"noun":"platform_payment_method","address":"583","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/billing/checkout-link","http_method":"POST","dispatch_endpoint":null},{"name":"billing.list_invoices","description":"Billing — list this company's Solid# invoices, most recent first (real BillingInvoice rows; previously always returned an empty list).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","default":20,"minimum":1,"maximum":100}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"581","noun":"platform_invoice","acts_on":{"noun":"platform_invoice","address":"581","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/billing/list-invoices","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"invoices":{},"limit":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"block.schema","description":"Return the canonical CMS block schema — the section/block types a page body is built from, with their shapes. Call this BEFORE edit_page_content so the layout_json you write matches what the renderer expects. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"79","noun":"block","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/block/schema","http_method":"POST","dispatch_endpoint":null},{"name":"blog.archive","description":"Take a tenant blog post (blog_posts, by post_id) off the site into the archive, recoverably: stamps deleted_at, unpublishes it, clears any pending schedule and trashes its mirrored CMS page. Nothing is destroyed; blog.restore brings it back as a draft. An archived post cannot be edited or published until restored. For permanent removal use blog_delete.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":"blog.restore","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/archive","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog.create","description":"Create a blog post (a draft unless published=true). The slug defaults to one made from the title and must be unused in this company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"content":{"type":"string","minLength":1},"slug":{"type":"string","nullable":true},"excerpt":{"type":"string","nullable":true},"featured_image":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"category":{"type":"string","nullable":true,"description":"default 'general'"},"author":{"type":"string","nullable":true,"description":"default 'Staff'"},"published":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"seo_title":{"type":"string","nullable":true,"description":"SEO title override (50-60 chars ideal)"},"seo_description":{"type":"string","nullable":true,"description":"Meta description (150-160 chars ideal)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","title"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"archived":{},"post_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog.delete","description":"PERMANENTLY delete a blog post (hard delete — NOT reversible) and remove its mirrored website page. Requires the owner to type the approval phrase shown in the preview. To take a post down recoverably, use blog.archive (blog.restore undoes it).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to permanently delete."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/delete","http_method":"POST","dispatch_endpoint":null},{"name":"blog.edit","description":"Edit an existing blog post's title, content, category, excerpt, author, or featured flag. Pass only the fields to change; omitted fields are left unchanged. Does not change the published state — use blog_publish / blog_unpublish for that.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to edit."},"title":{"type":"string","minLength":1,"maxLength":500},"content":{"type":"string","minLength":1,"description":"Blog body (HTML or markdown)."},"category":{"type":"string","minLength":1,"maxLength":100},"excerpt":{"type":"string","maxLength":1000},"author":{"type":"string","maxLength":255},"featured":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/edit","http_method":"POST","dispatch_endpoint":null},{"name":"blog.generate","description":"AI-generate a full blog post for this company from its brand voice and knowledge base. Optionally seed a title/topic or a target SEO keyword. Defaults to a draft; pass publish=true to publish immediately if it passes brand review. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Optional seed title or topic."},"keyword":{"type":"string","description":"Optional target SEO keyword."},"publish":{"type":"boolean","description":"Publish immediately if brand review passes. Default false (draft)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/generate","http_method":"POST","dispatch_endpoint":null},{"name":"blog.post_create","description":"Create a blog post. Defaults to draft (published=false) so the user can review before going live; pass published=true to publish immediately. Slug must be lowercase-alphanum + dashes. Category is required (e.g. 'news', 'how-to', 'announcements').","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug. Lowercase alphanumeric + dashes. 1–255 chars.","minLength":1,"maxLength":255},"title":{"type":"string","minLength":1,"maxLength":500},"content":{"type":"string","minLength":1,"description":"Blog body (HTML or markdown)."},"category":{"type":"string","minLength":1,"maxLength":100},"author":{"type":"string","description":"Author name. Default 'Staff'.","maxLength":255},"excerpt":{"type":"string","description":"Short summary. Optional.","maxLength":1000},"published":{"type":"boolean","description":"Default false (draft)."},"featured":{"type":"boolean","description":"Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","title","content","category"]},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/post-create","http_method":"POST","dispatch_endpoint":null},{"name":"blog.publish","description":"Publish a blog post. Re-publishing keeps its original publish date.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":"blog.unpublish","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/publish","http_method":"POST","dispatch_endpoint":null},{"name":"blog.restore","description":"Bring an archived tenant blog post (by post_id) back as a DRAFT — restoring never re-publishes; publish it again with blog.publish. A post that is already live comes back as its receipt with already_active=true; blog_post_not_archived means no post with that id exists.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":"blog.archive","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/restore","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog.unpublish","description":"Sets a tenant blog post (blog_posts, by post_id) back to draft and syncs the CMS listing. Keeps its original published_at. Returns post_id, title, slug and published=false.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":"blog.publish","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/unpublish","http_method":"POST","dispatch_endpoint":null},{"name":"blog.update","description":"Update a blog post — only the fields given. Publishing is blog.publish / blog.unpublish.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"content":{"type":"string","nullable":true},"excerpt":{"type":"string","nullable":true},"featured_image":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"author":{"type":"string","nullable":true},"featured":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"cms:blog:write","transport":"http","coordinate":"85","noun":"blog","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blog/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_delete","description":"PERMANENTLY delete a blog post (hard delete — NOT reversible) and remove its mirrored website page. Requires the owner to type the approval phrase shown in the preview. To take a post down recoverably, use blog.archive (blog.restore undoes it).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to permanently delete."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.delete","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"deleted":{},"ok":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_edit","description":"Edit an existing blog post's title, content, category, excerpt, author, or featured flag. Pass only the fields to change; omitted fields are left unchanged. Does not change the published state — use blog_publish / blog_unpublish for that.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to edit."},"title":{"type":"string","minLength":1,"maxLength":500},"content":{"type":"string","minLength":1,"description":"Blog body (HTML or markdown)."},"category":{"type":"string","minLength":1,"maxLength":100},"excerpt":{"type":"string","maxLength":1000},"author":{"type":"string","maxLength":255},"featured":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.edit","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"ok":{},"preflight":{},"slug":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_generate","description":"AI-generate a full blog post for this company from its brand voice and knowledge base. Optionally seed a title/topic or a target SEO keyword. Defaults to a draft; pass publish=true to publish immediately if it passes brand review. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Optional seed title or topic."},"keyword":{"type":"string","description":"Optional target SEO keyword."},"publish":{"type":"boolean","description":"Publish immediately if brand review passes. Default false (draft)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.generate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"ok":{},"published":{},"review":{},"slug":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_post_create","description":"Create a blog post. Defaults to draft (published=false) so the user can review before going live; pass published=true to publish immediately. Slug must be lowercase-alphanum + dashes. Category is required (e.g. 'news', 'how-to', 'announcements').","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug. Lowercase alphanumeric + dashes. 1–255 chars.","minLength":1,"maxLength":255},"title":{"type":"string","minLength":1,"maxLength":500},"content":{"type":"string","minLength":1,"description":"Blog body (HTML or markdown)."},"category":{"type":"string","minLength":1,"maxLength":100},"author":{"type":"string","description":"Author name. Default 'Staff'.","maxLength":255},"excerpt":{"type":"string","description":"Short summary. Optional.","maxLength":1000},"published":{"type":"boolean","description":"Default false (draft)."},"featured":{"type":"boolean","description":"Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","title","content","category"]},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.post_create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"company_id":{},"ok":{},"preflight":{},"published":{},"slug":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_publish","description":"Publish a draft blog post (sets published=true and published_at=NOW). Idempotent — re-publishing an already-published post is a no-op success. The post must already exist; use blog_post_create to create + publish in one shot.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to publish."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.publish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"ok":{},"preflight":{},"published":{},"slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blog_unpublish","description":"Revert a published blog post to draft (published=false). Idempotent — unpublishing a draft is a no-op success. The post must already exist.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"blog_posts.id to unpublish."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"cms:blog:write","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"blog.unpublish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"blog_post_id":{},"ok":{},"preflight":{},"published":{},"slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blueprint.classify","description":"B.L.U.E.P.R.I.N.T. step 1: classify the tenant by reading its KB. Returns industry / intent / customer type / primary CTA / self-classification statement. Always call this before building pages.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"04","noun":"blueprint","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blueprint/classify","http_method":"POST","dispatch_endpoint":null},{"name":"blueprint.content_strategy","description":"Return SEO + content-strategy recommendations for the tenant based on its B.L.U.E.P.R.I.N.T. classification.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"04","noun":"blueprint","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blueprint/content-strategy","http_method":"POST","dispatch_endpoint":null},{"name":"blueprint.journey","description":"B.L.U.E.P.R.I.N.T. step 2: return the full journey map — classification + ordered page list with per-page role / blocks / SEO notes. Use this as the website-build blueprint.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"required_only":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"04","noun":"blueprint","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blueprint/journey","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company":{},"customer_type":{},"intent":{},"journey_name":{},"page_count":{},"pages":{},"primary_cta":{},"required_only":{},"secondary_cta":{},"statement":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blueprint.journeys_list","description":"Catalog of every available journey-map template (read-only — does not write the tenant's classification).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"04","noun":"blueprint","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blueprint/journeys-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"journeys":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"blueprint.navigation","description":"Return the recommended header + footer navigation structure for the tenant's journey map.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"04","noun":"blueprint","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/blueprint/navigation","http_method":"POST","dispatch_endpoint":null},{"name":"books.revenue_summary","description":"Return this company's revenue summary for the last N days. Reports TWO ledgers under `summary`: order_revenue/total_revenue (collected checkout/POS/ecommerce orders) and closed_deal_revenue (booked value of won/paid CRM deals — how sales-led businesses earn), plus total_sales (both combined) and closed_deal_revenue_all_time. Read-only. If order_revenue is 0, check closed_deal_revenue before reporting '$0 sales'. DO NOT fabricate numbers.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","description":"Lookback window in days. Default 30.","minimum":1,"maximum":365}}},"required_scope":null,"transport":"http","coordinate":"500","noun":"books","acts_on":{"noun":"books","address":"500","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/books/revenue-summary","http_method":"POST","dispatch_endpoint":null},{"name":"books.summary","description":"The books in one picture from Solid#'s own records — with or without an accounting system: invoiced and collected, spent and billed, what customers owe you and what you owe (with how much is overdue). Basis: invoices by issue date, purchases by purchase date.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string"},"until":{"type":"string"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"500","noun":"books","acts_on":{"noun":"books","address":"500","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/books/summary","http_method":"POST","dispatch_endpoint":null},{"name":"brand.compile","description":"Compile this company's brand into CSS custom properties and report where they came from: `source` is \"brand\", \"website_settings\", or \"defaults\" — and \"defaults\" means the tenant has configured nothing and the page will render in Solid# colours. persist=true writes a derived palette into the brand record the renderer already reads.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"persist":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":"brand:read","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/compile","http_method":"POST","dispatch_endpoint":null},{"name":"brand.create","description":"Create a brand for a company (one per company).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"design":{"type":"object"},"voice":{"type":"object"},"rules":{"type":"object"},"source_url":{"type":"string"},"extraction_method":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"brand:write","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"brand":{},"error":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"brand.export","description":"Export brand as CSS, Tailwind config, or JSON.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"format":{"type":"string"}}},"required_scope":"brand:read","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/export","http_method":"POST","dispatch_endpoint":null},{"name":"brand.generate_palette","description":"Generate a full color palette from a single primary color.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"primary_color":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["primary_color"]},"required_scope":"brand:write","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/generate-palette","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"palette":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"brand.get","description":"Reads the company's brand: name, logo_url, tagline and primary/secondary colours from website_settings, falling back to the brands row colours. Read-only; takes no input.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"brand:read","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"brand_name":{},"company_id":{},"logo_url":{},"primary_color":{},"secondary_color":{},"status":{},"tagline":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"brand.set_tokens","description":"Set this company's brand DESIGN tokens. Pass any of colors / typography / shape / assets as objects — they DEEP-MERGE into the current brand (send only what changes). Colors are hex; typography is font families + scale.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"colors":{"type":"object","description":"e.g. {\"primary\":\"#0EA5E9\",\"accent\":\"#F97316\"}."},"typography":{"type":"object","description":"e.g. {\"heading_font\":\"Inter\",\"body_font\":\"Inter\"}."},"shape":{"type":"object","description":"e.g. {\"border_radius\":\"1rem\"}."},"assets":{"type":"object","description":"e.g. {\"logo_url\":\"...\",\"favicon\":\"...\"}."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"brand:write","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/set-tokens","http_method":"POST","dispatch_endpoint":null},{"name":"brand.set_truth","description":"Set this company's brand truth — the voice/positioning the AI grounds on: tone, target audience, mission, unique selling proposition, personality, values, and preferred/forbidden words. Pass only the fields to change; one record per company (upsert).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tone":{"type":"string","description":"e.g. professional, friendly, luxury."},"target_audience":{"type":"string"},"company_mission":{"type":"string"},"unique_selling_proposition":{"type":"string"},"brand_personality":{"type":"array","items":{"type":"string"},"description":"e.g. ['innovative','trustworthy']."},"company_values":{"type":"array","items":{"type":"string"}},"preferred_keywords":{"type":"array","items":{"type":"string"}},"forbidden_words":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"brand:write","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/set-truth","http_method":"POST","dispatch_endpoint":null},{"name":"brand.tokens","description":"Get this company's brand DESIGN tokens — colors, typography, and shape — so designs stay on-brand. (Brand voice/tone is get_brand_truth.) Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"brand:read","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/tokens","http_method":"POST","dispatch_endpoint":null},{"name":"brand.update","description":"Brand — set this company's name, logo and brand colours. ⭐ One call writes BOTH brand stores: the `brands` row (the design tokens the renderer reads through Brand.get_css_variables) AND companies.name / logo_url / website_settings. The change is versioned and rollback-able. Pass `design` to set any design token — every colour (primary, secondary, accent, background, surface, text_primary, text_secondary, …), typography, shape, assets. It merges per section into what exists, so changing fonts never wipes the palette; an unknown section is refused, never dropped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"brand_name":{"nullable":true,"type":"string"},"logo_url":{"nullable":true,"type":"string"},"primary_color":{"nullable":true,"type":"string"},"secondary_color":{"nullable":true,"type":"string"},"tagline":{"nullable":true,"type":"string"},"design":{"nullable":true,"type":"object","description":"Design tokens by section: {colors:{…}, typography:{…}, shape:{…}, assets:{…}}. Merged per section."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"brand:write","transport":"http","coordinate":"77","noun":"brand","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"unknown_design_section","when":"design has a key other than colors, typography, shape or assets, or a section is not an object; nothing changes.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/brand/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"brand_id":{},"brand_name":{},"company_id":{},"design":{},"logo_url":{},"primary_color":{},"secondary_color":{},"status":{},"tagline":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call.handoff","description":"Hand a live call to a person or the AI. On a call waiting for a decision (a line set to 'You choose'): action 'take' rings me — ring 'app' my web app, ring 'cell' my cell from call settings; 'ai' hands the caller to the line's agent; 'voicemail' takes a message. On a call the AI is already handling: action 'take' takes it over — the agent tells the caller it is getting me, then my phone rings. Only the line's person or an admin may decide; a call already decided returns gone.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_sid":{"type":"string","description":"The call's Twilio SID (from the call card or voice.active_calls)."},"action":{"type":"string","enum":["take","ai","voicemail"]},"ring":{"type":"string","enum":["app","cell"],"description":"Where 'take' rings me. Default app."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_sid","action"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call/handoff","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action":{},"call_id":{},"detail":{},"error":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call.list_recent","description":"List recent voice calls for this company — the most recent first. By default returns the latest calls regardless of age; pass `days` to limit to a recent window. Returns id, direction, from/to numbers, duration, status, summary preview. Read-only. Use when the user asks 'what calls came in' or 'show me last week's calls'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"description":"Optional lookback window in days. Omit to get the most recent calls regardless of age."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"Optional filter."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."}}},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call/list-recent","http_method":"POST","dispatch_endpoint":null},{"name":"call.recording_url","description":"Return the recording URL for a voice call. The URL is taken from VoiceCall.recording_url (decrypted). Treat as short-TTL and don't log it; surface to the user via the confirmation card. Owner/admin only — recordings are sensitive.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_id"]},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call/recording-url","http_method":"POST","dispatch_endpoint":null},{"name":"call.transcript_full","description":"Fetch the full transcript text of a voice call (decrypted on read). Use when summary isn't enough — disputes, quote extraction, compliance review. Returns large text; expect 5-50k chars.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer","description":"voice_calls.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_id"]},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call/transcript-full","http_method":"POST","dispatch_endpoint":null},{"name":"call_flow.bind","description":"Point a phone line's tree at a saved flow (voice_config.call_flow_id) — or unbind with flow_id=null. Archived flows and PINNED lines are refused. As of 2026-09-09 the runtime EXECUTES bound flows: binding one changes what a real caller hears. ALL route types run — submenu/repeat/take_message/ai continue the conversation, and user/department/voicemail/hangup actually move the caller. A department named with no number and nobody assigned reaches nothing: that caller is offered a message instead, and switchboard.simulate reports it under unreachable_routes before it happens.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"flow_id":{"type":"integer","nullable":true,"description":"null unbinds"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"pinned_line","when":"The line is pinned — its routing is a code-level decision.","override":null,"code_in_response":true},{"code":"flow_archived","when":"The flow being bound is archived (unbinding with flow_id=null is never refused).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call_flow/bind","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"bound":{},"call_flow_id":{},"detail":{},"error":{},"line_id":{},"phone_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call_flow.get","description":"List this company's phone trees / call flows (id, name, status, node count, and which lines are bound to each). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","active","archived"],"description":"Optional status filter. Default all."}}},"required_scope":"voice:read","transport":"http","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call_flow/get","http_method":"POST","dispatch_endpoint":null},{"name":"call_flow.list","description":"The company's phone trees: id, name, status (draft|active|archived), node count, and which lines each is bound to. Read-only — the Phone Tree builder's index.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true,"enum":["draft","active","archived"]}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call_flow/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"flows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call_flow.save","description":"Create or update a phone tree (multi-node: prompt + digit/intent routes → agent/user/department/submenu/voicemail/hangup/ai). The flow is validated BEFORE persisting — an invalid tree is refused with flow_errors, so every stored flow is runtime-safe. A department may be saved with only a name (naming teams before wiring them is allowed), but it will reach nobody on a real call — switchboard.simulate lists those under unreachable_routes. Follow with switchboard.simulate to test-dial it and call_flow.bind to put it on a line.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"flow":{"type":"object"},"flow_id":{"type":"integer","nullable":true,"description":"update this flow; omit to create"},"description":{"type":"string","nullable":true},"status":{"type":"string","nullable":true,"enum":["draft","active","archived"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","flow"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_flow","when":"The flow fails validation (unreachable node, bad route, missing agent_id, …); flow_errors lists each, nothing is saved.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/call_flow/save","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"flow_errors":{},"flow_id":{},"saved":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call_flow_get","description":"List this company's phone trees / call flows (id, name, status, node count, and which lines are bound to each). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","active","archived"],"description":"Optional status filter. Default all."}}},"required_scope":"voice:read","transport":"dispatch","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"call_flow.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"call_flow_save","description":"Create or update a phone tree / call flow. The flow graph is validated before it persists — an invalid tree is refused with the errors, never stored. Pass flow_id to update an existing tree; omit to create one.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Flow name."},"flow":{"type":"object","description":"The phone-tree node graph (JSON)."},"flow_id":{"type":"integer","description":"Existing flow id to update; omit to create."},"description":{"type":"string"},"status":{"type":"string","enum":["draft","active","archived"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","flow"]},"required_scope":"voice:write","transport":"dispatch","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"call_flow.save","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"call_recording_url","description":"Return the recording URL for a voice call. The URL is taken from VoiceCall.recording_url (decrypted). Treat as short-TTL and don't log it; surface to the user via the confirmation card. Owner/admin only — recordings are sensitive.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_id"]},"required_scope":"voice:read","transport":"dispatch","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"call.recording_url","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"call_id":{},"duration_seconds":{},"has_recording":{},"preflight":{},"recording_url":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"call_transcript_full","description":"Fetch the full transcript text of a voice call (decrypted on read). Use when summary isn't enough — disputes, quote extraction, compliance review. Returns large text; expect 5-50k chars.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer","description":"voice_calls.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_id"]},"required_scope":"voice:read","transport":"dispatch","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"call.transcript_full","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"call_id":{},"direction":{},"duration_seconds":{},"has_transcript":{},"preflight":{},"status":{},"transcript":{},"transcript_length":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"campaign.schedule","description":"Schedule a campaign to send at a future ISO datetime. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer"},"send_at":{"type":"string","description":"ISO 8601 send time."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id","send_at"]},"required_scope":"marketing:write","transport":"http","coordinate":"670","noun":"email_campaign","acts_on":{"noun":"email_campaign","address":"670","domain":"Campaigns, automations & channel rules","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/campaign/schedule","http_method":"POST","dispatch_endpoint":null},{"name":"campaign.send","description":"Send an email campaign: a saved one by campaign_id, or a new one from subject, html_body and CRM recipient_ids. Queues the send and returns; each recipient is checked against the suppression list and marketing consent as it goes out.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","nullable":true,"description":"a saved campaign; omit to send a new one"},"subject":{"type":"string","nullable":true},"html_body":{"type":"string","nullable":true},"recipient_ids":{"type":"array","items":{"type":"integer"},"nullable":true},"sender_name":{"type":"string","nullable":true},"campaign_name":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"670","noun":"email_campaign","acts_on":{"noun":"email_campaign","address":"670","domain":"Campaigns, automations & channel rules","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/campaign/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign_id":{},"reason":{},"recipient_count":{},"status":{},"summary":{},"task_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"campaign_schedule","description":"Schedule a campaign to send at a future ISO datetime. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer"},"send_at":{"type":"string","description":"ISO 8601 send time."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id","send_at"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"670","noun":"email_campaign","acts_on":{"noun":"email_campaign","address":"670","domain":"Campaigns, automations & channel rules","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"campaign.schedule","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"campaign_id":{},"preflight":{},"send_at":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"campaign_send","description":"Send a previously-saved email campaign immediately. The campaign must already exist with segment + content set. Admin role + typed phrase (it's bulk PII outbound).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"670","noun":"email_campaign","acts_on":{"noun":"email_campaign","address":"670","domain":"Campaigns, automations & channel rules","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"campaign.send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"campaign_id":{},"celery_task_id":{},"name":{},"preflight":{},"recipient_count":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capability.set","description":"Record whether this company offers a specific capability/service, so the AI answers callers correctly. offered=true means 'we do this'; offered=false means 'we explicitly do NOT' (prevents the AI from over-promising).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","description":"Grouping, e.g. 'services', 'payment', 'hours'."},"capability_name":{"type":"string","description":"The capability, e.g. 'emergency service'."},"offered":{"type":"boolean","description":"True = offered, False = explicitly not offered. Default true."},"details":{"type":"string","description":"Optional detail shown to the AI."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["category","capability_name"]},"required_scope":"ops:write","transport":"http","coordinate":"17","noun":"capability","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capability/set","http_method":"POST","dispatch_endpoint":null},{"name":"capture.attach","description":"Put a photo from the camera (or any stored file) where it belongs: onto a job (target='deal', target_id=the deal), onto a customer's timeline (target='contact', target_id=the CRM contact — a note carrying the photo is added), onto a catalog product once the owner confirms it is that item (target='product', target_id=the product — this is how ADA learns to recognise it by look), or just keep it in Files (target='files'). Moves it out of the unsorted inbox either way.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1},"target":{"type":"string","enum":["deal","contact","product","files"]},"target_id":{"type":"integer","minimum":1,"description":"The deal, CRM contact or product. Not needed for 'files'."},"note":{"type":"string","maxLength":2000,"description":"What to say about it on the customer's timeline."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id","target"]},"required_scope":"files:write","transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/attach","http_method":"POST","dispatch_endpoint":null},{"name":"capture.card_present_rails","description":"Which card-present rails this merchant can use — Tap to Pay on iPhone, Tap to Pay on Android, and a countertop terminal — reported SEPARATELY, each with what is still missing in plain words. A merchant approved for Android and not iPhone is a normal state one boolean cannot express.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/card-present-rails","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"available":{},"card_present_ready":{},"company_id":{},"location_id":{},"note":{},"rails":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture.classify","description":"Show ADA — look at one of the company's files (a photo from the camera, or any stored image or PDF) and say what it is: kind, a one-or-two sentence guess in the owner's language, the action to put first, and what she could read (item, amount, vendor, person, code). Returns the full ordered action fan from capture.options with her guess leading. A guess under the confidence floor loses its lead and says so; nothing that is not visible is invented. This is NOT the OCR — reading fields is document_extract, which spends a credit.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1},"lang":{"type":"string","enum":["en","es","de","fr","pt"],"default":"en"}},"required":["document_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/classify","http_method":"POST","dispatch_endpoint":null},{"name":"capture.context","description":"Save a durable fact the OWNER just told you about their business — a policy, the answer to a common question, how they do something, their service area — into the knowledge base, so every future session, the voice line, the chat widget, and every connected app inherit it. Use this the moment you LEARN something from the owner that isn't documented yet, so it isn't lost when this chat ends. Pass `question` when it's a Q&A the AI should be able to answer for customers. Confirmation-gated: nothing saves until the owner approves. NEVER capture guesses or general knowledge — only what the owner actually stated.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","description":"The fact/answer in the owner's own words (min 3 chars)."},"question":{"type":"string","description":"Optional — the customer question this answers, if it's a FAQ."},"category":{"type":"string","description":"Optional topic, e.g. 'services', 'policies', 'pricing'. Default 'general'."},"source_app":{"type":"string","description":"Optional — which app learned it (e.g. 'claude', 'chatgpt'), for provenance."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content"]},"required_scope":"files:write","transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/context","http_method":"POST","dispatch_endpoint":null},{"name":"capture.files","description":"Show ADA — the photos and files that were put on one job (target='deal') or one customer (target='contact') with capture_attach, newest first, with ADA's one-line summary of each.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_id":{"type":"integer","minimum":1},"target":{"type":"string","enum":["deal","contact"]},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"required":["target_id","target"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/files","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"items":{},"message":{},"target":{},"target_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture.methods","description":"What this merchant can actually take money with right now — tap, terminal, card on file, text to pay, cash, cheque, phone. Ask instead of assuming: offering tap-to-pay to a merchant with no reader wastes the customer's time at the worst moment.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"device_id":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/methods","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"methods":{},"processor":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture.options","description":"Show ADA — what to offer after the camera captures something (a photo, a document, a scanned code or a video), for THIS business, in order. Only the actions its industry actually uses are returned (a clinic is never offered a bid), labelled with the company's own words ('Save it to a case' for a law firm, 'a job' for a plumber), each naming the verb that performs it. Pass `lead` — an action id from capture.classify — to put ADA's guess first; an action the business does not do cannot be led. `terms` returns the company's nouns in `lang` for clients that compose translated labels.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["photo","document","code","video"],"default":"photo"},"lang":{"type":"string","enum":["en","es","de","fr","pt"],"default":"en"},"lead":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/options","http_method":"POST","dispatch_endpoint":null},{"name":"capture.partial","description":"Capture a portion of a prior authorization. Some processors (Stripe, Adyen, Braintree) support auth-then-partial-capture; others reject. Returns op_not_supported_by_adapter if the company's processor lacks the method. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string","description":"Authorization id"},"amount_cents":{"type":"integer","minimum":1},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id","amount_cents"]},"required_scope":"files:write","transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"processor_not_connected","when":"The named processor is not connected.","override":null,"code_in_response":true},{"code":"no_processor_connected","when":"No payment processor is connected.","override":null,"code_in_response":true},{"code":"adapter_not_connected","when":"The processor has no credentials for this environment, or a test processor is on a live connection.","override":null,"code_in_response":true},{"code":"op_not_supported_by_adapter","when":"The connected processor's adapter cannot partially capture.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/partial","http_method":"POST","dispatch_endpoint":null},{"name":"capture.rail_requirements","description":"What a card-present rail requires — hardware, approvals, and what it does NOT need. Independent of any merchant, so onboarding can show what someone is signing up for. Android tap does not require Apple's entitlement; a terminal requires no phone at all.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"rail":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/rail-requirements","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"rail":{},"rails":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture.set_phone_connector","description":"Turn phone card capture on or off. Takes the name of a Pay Connector configured in the merchant's OWN Twilio account — a name, never a credential. Null switches it off, and off is the safe default: without a connector the card capture would prompt the caller and then fail after they had read their card aloud.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"connector":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"80","noun":"capture","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/capture/set-phone-connector","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connector":{},"error":{},"note":{},"ok":{},"phone_capture_enabled":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture_attach","description":"Put a photo from the camera (or any stored file) where it belongs: onto a job (target='deal', target_id=the deal), onto a customer's timeline (target='contact', target_id=the CRM contact — a note carrying the photo is added), onto a catalog product once the owner confirms it is that item (target='product', target_id=the product — this is how ADA learns to recognise it by look), or just keep it in Files (target='files'). Moves it out of the unsorted inbox either way.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1},"target":{"type":"string","enum":["deal","contact","product","files"]},"target_id":{"type":"integer","minimum":1,"description":"The deal, CRM contact or product. Not needed for 'files'."},"note":{"type":"string","maxLength":2000,"description":"What to say about it on the customer's timeline."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id","target"]},"required_scope":"files:write","transport":"dispatch","coordinate":"80","noun":"capture","location":"svc.api","same_as":"capture.attach","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"document_id":{},"note_id":{},"ok":{},"preview":{},"target":{},"target_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"capture_context","description":"Save a durable fact the OWNER just told you about their business — a policy, the answer to a common question, how they do something, their service area — into the knowledge base, so every future session, the voice line, the chat widget, and every connected app inherit it. Use this the moment you LEARN something from the owner that isn't documented yet, so it isn't lost when this chat ends. Pass `question` when it's a Q&A the AI should be able to answer for customers. Confirmation-gated: nothing saves until the owner approves. NEVER capture guesses or general knowledge — only what the owner actually stated.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","description":"The fact/answer in the owner's own words (min 3 chars)."},"question":{"type":"string","description":"Optional — the customer question this answers, if it's a FAQ."},"category":{"type":"string","description":"Optional topic, e.g. 'services', 'policies', 'pricing'. Default 'general'."},"source_app":{"type":"string","description":"Optional — which app learned it (e.g. 'claude', 'chatgpt'), for provenance."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content"]},"required_scope":"kb:write","transport":"dispatch","coordinate":"80","noun":"capture","location":"svc.api","same_as":"capture.context","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"deduped":{},"event_id":{},"kb_id":{},"preflight":{},"status":{},"title":{},"would_capture":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"card_on_file.swap_token","description":"Re-tokenize a saved payment method (e.g., processor migration or token expiry). Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"old_token":{"type":"string"},"contact_id":{"type":"integer"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["old_token"]},"required_scope":"ops:write","transport":"http","coordinate":"532","noun":"card_on_file","acts_on":{"noun":"card_on_file","address":"532","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/card_on_file/swap-token","http_method":"POST","dispatch_endpoint":null},{"name":"cart.add_item","description":"Adds a product line to a tenant cart (cart_items), snapshotting name, SKU and price (or the given price), then recomputes the cart subtotal and total. Requires cart_id and product_id; returns cart_item_id and line_total.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cart_id":{"type":"integer","minimum":1},"product_id":{"type":"integer","minimum":1},"quantity":{"type":"integer","minimum":1,"default":1},"price":{"type":"number","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["cart_id","product_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"49","noun":"cart","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cart/add-item","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cart_id":{},"cart_item_id":{},"line_total":{},"product":{},"quantity":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cart.create","description":"Opens a new active shopping cart (carts table) for the tenant, optionally tied to contact_id. Returns the new cart_id; add lines with cart.add_item.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"49","noun":"cart","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cart/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cart_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"catalog.confirm_price_basis","description":"Record which price imported catalog prices are — basis \"cash\" or \"card\" (the card difference already in it) — for listed items [{kind: product|service, id}] or all_unconfirmed. Each is re-stored as the program's posted price, so both prices show correctly everywhere. Only unconfirmed prices change.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"basis":{"type":"string","enum":["cash","card"]},"items":{"type":"array","items":{"type":"object"},"nullable":true},"all_unconfirmed":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["basis"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/catalog/confirm-price-basis","http_method":"POST","dispatch_endpoint":null},{"name":"catalog.match_image","description":"Show ADA — \"do I have this?\": the company's own products a photo (document_id from the camera), some words (terms) or a scanned code most likely are, best first, with price, units on hand and stock by location. Matches by words today (name, SKU, UPC, model number, tags, category); every answer says visual='not_built' until matching by look ships. Reading a photo spends one vision call — pass terms from capture.classify's `match` to skip it. No match is an honest empty list.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1},"terms":{"type":"array","items":{"type":"string"},"maxItems":8},"code":{"type":"string"},"lang":{"type":"string","enum":["en","es","de","fr","pt"],"default":"en"},"limit":{"type":"integer","minimum":1,"maximum":20,"default":5}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/catalog/match-image","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"in_stock":{},"matches":{},"message":{},"method":{},"searched":{},"visual":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"catalog.search","description":"The company's services AND products, best match first, by words (name, SKU, category, tags) — what \"I need X and a Y\" is priced from (whatever this company sells), and the document builder's catalog picker. Each hit carries price, cost when known, and `add_with` — pass it to proposals.add_item and the line takes the catalog's name, price and cost. An empty query lists the catalog. Company-scoped.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/catalog/search","http_method":"POST","dispatch_endpoint":null},{"name":"catalog.unconfirmed_prices","description":"Products and services whose price came from an import or another system and nobody has said whether it is the cash price or the card price (price_basis unknown). Ask the owner once, then catalog.confirm_price_basis.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":500,"default":100}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/catalog/unconfirmed-prices","http_method":"POST","dispatch_endpoint":null},{"name":"chain.activate","description":"Sets an automation chain (chain_definitions, by chain_id) to status active. Only flips the status; it does not run the chain. Returns chain_id and name.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"chain_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["chain_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"05","noun":"chain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chain/activate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chain_id":{},"name":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chain.create","description":"Creates a draft agent chain (chain_definitions) from a name and steps; an optional trigger (\"manual\" or an event type) is stored in triggers. Returns chain_id; activate before executing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"steps":{"type":"array","items":{"type":"object"},"minItems":1},"description":{"type":"string","nullable":true},"trigger":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","steps"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"05","noun":"chain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chain/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chain_id":{},"chain_status":{},"name":{},"note":{},"status":{},"step_count":{},"summary":{},"triggers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chain.execute","description":"Run a chain through ChainOrchestrator and return its real terminal execution state. Agent-type steps run through the real agent conversation pipeline (agent_bridge); a step naming an agent this company has not provisioned fails the chain rather than completing. The legacy agent_steps_simulated key in the response is always False.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"chain_id":{"type":"integer","minimum":1},"input_data":{"type":"object","nullable":true},"timeout_seconds":{"type":"integer","minimum":1,"maximum":3600,"default":300},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["chain_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"05","noun":"chain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chain/execute","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_step_count":{},"agent_steps_simulated":{},"chain_id":{},"errors":{},"execution_id":{},"finished":{},"name":{},"outputs":{},"status":{},"step_count":{},"steps_completed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chain.list","description":"Lists the tenant's automation chains (chain_definitions), newest first, optionally filtered by status, up to limit (default 50). Returns id, name, status and description per chain.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"05","noun":"chain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chain/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chains":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chain.pause","description":"Sets an automation chain (chain_definitions, by chain_id) to status paused so it stops being eligible to run. Returns chain_id, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"chain_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["chain_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"05","noun":"chain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chain/pause","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chain_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"changes.approve","description":"Approve a pending AI/agent change: run the queued action and publish it. Only owners/admins/managers (write.approve) may approve.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The pending change id to approve."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"changes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/changes/approve","http_method":"POST","dispatch_endpoint":null},{"name":"changes.get","description":"Get one AI/agent change by id — full diff, reversibility, status, and links (entity, version, receipt, audit). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The proposed-change id."}},"required":["change_id"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"changes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/changes/get","http_method":"POST","dispatch_endpoint":null},{"name":"changes.list","description":"List recent AI/agent changes for this company — the write-safety queue. Shows each change's verb, reversibility (reversible vs cannot-be-undone), status, and a diff. Optionally filter by status. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Optional status filter: previewed, staged, pending_approval, approved, published, rejected, rolled_back, expired."},"limit":{"type":"integer","description":"Max rows (default 50, max 200)."}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"changes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/changes/list","http_method":"POST","dispatch_endpoint":null},{"name":"changes.reject","description":"Reject a pending AI/agent change so it never executes. Only owners/admins/managers (write.approve) may reject.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The pending change id to reject."},"reason":{"type":"string","description":"Optional reason for the rejection."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"changes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_pending","when":"The change is not pending approval (already published, rejected, rolled back or expired).","override":null,"code_in_response":true},{"code":"discard_failed","when":"The change was staged in an open sandbox and removing it failed; it stays pending.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/changes/reject","http_method":"POST","dispatch_endpoint":null},{"name":"changes.rollback","description":"Undo a published, reversible AI/agent change — restores the affected record to its state before the change (via version history). Irreversible changes (sent email/SMS, charges) cannot be undone. Requires write.rollback.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The published change id to undo."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"changes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_published","when":"Only a published change can be rolled back.","override":null,"code_in_response":true},{"code":"irreversible","when":"The change is not reversible (a sent email or text, a charge).","override":null,"code_in_response":true},{"code":"no_entity_link","when":"The change is not linked to an entity — use history.rollback instead.","override":null,"code_in_response":true},{"code":"no_version","when":"The entity has no version history to restore.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/changes/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"changes_approve","description":"Approve a pending AI/agent change: run the queued action and publish it. Only owners/admins/managers (write.approve) may approve.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The pending change id to approve."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"changes","location":"svc.api","same_as":"changes.approve","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"changes_get","description":"Get one AI/agent change by id — full diff, reversibility, status, and links (entity, version, receipt, audit). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The proposed-change id."}},"required":["change_id"]},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"changes","location":"svc.api","same_as":"changes.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"change":{},"change_id":{},"found":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"changes_list","description":"List recent AI/agent changes for this company — the write-safety queue. Shows each change's verb, reversibility (reversible vs cannot-be-undone), status, and a diff. Optionally filter by status. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Optional status filter: previewed, staged, pending_approval, approved, published, rejected, rolled_back, expired."},"limit":{"type":"integer","description":"Max rows (default 50, max 200)."}}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"changes","location":"svc.api","same_as":"changes.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"changes":{},"count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"changes_reject","description":"Reject a pending AI/agent change so it never executes. Only owners/admins/managers (write.approve) may reject.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The pending change id to reject."},"reason":{"type":"string","description":"Optional reason for the rejection."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"changes","location":"svc.api","same_as":"changes.reject","status":"active","inverse":null,"refuses_when":[{"code":"not_pending","when":"The change is not pending approval (already published, rejected, rolled back or expired).","override":null,"code_in_response":true},{"code":"discard_failed","when":"The change was staged in an open sandbox and removing it failed; it stays pending.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"change_id":{},"discarded_from_sandbox":{},"error":{},"message":{},"ok":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"changes_rollback","description":"Undo a published, reversible AI/agent change — restores the affected record to its state before the change (via version history). Irreversible changes (sent email/SMS, charges) cannot be undone. Requires write.rollback.","shape":"discovery","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"change_id":{"type":"integer","description":"The published change id to undo."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["change_id"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"changes","location":"svc.api","same_as":"changes.rollback","status":"active","inverse":null,"refuses_when":[{"code":"not_published","when":"Only a published change can be rolled back.","override":null,"code_in_response":true},{"code":"irreversible","when":"The change is not reversible (a sent email or text, a charge).","override":null,"code_in_response":true},{"code":"no_entity_link","when":"The change is not linked to an entity — use history.rollback instead.","override":null,"code_in_response":true},{"code":"no_version","when":"The entity has no version history to restore.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"charge_invoice","description":"Charge a tenant invoice through the company's connected payment processor. Processor-agnostic — routes through services/payments/registry.py and the company's MerchantAccount. Requires admin role + typed-phrase confirmation including the amount and invoice number.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"ID of the tenant invoice to charge (invoices.id)."},"amount_cents":{"type":"integer","description":"Amount to charge in cents (must equal or be less than amount_due).","minimum":1},"source_token":{"type":"string","description":"Payment source token (card token, payment_method_id, etc.) from the processor — supplied by the frontend / saved on the customer."},"processor":{"type":"string","description":"Optional override of the company's default processor. Use only when explicitly directed; default uses MerchantAccount.is_default=True."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","amount_cents","source_token"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice_payment.charge","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount_cents":{},"amount_display":{},"amount_to_charge":{},"charge_id":{},"error":{},"error_code":{},"invoice":{},"invoice_id":{},"preflight":{},"processor":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chat.send","description":"Reply into a website-chat conversation as the business — completes the send trio (sms.send / email.send / chat.send). Takes the unified-inbox thread id ('chat_<uuid>') or the bare conversation uuid; the reply lands on the thread, an unassigned thread is assigned to the replier (lightweight takeover), and the visitor sees it on the embed widget's next poll. Tenant-scoped; cross-tenant conversations read as not-found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"conversation_id":{"type":"string"},"message":{"type":"string"},"sender_name":{"type":"string","nullable":true,"description":"Display name shown beside the message. Defaults to the agent/company name."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["conversation_id","message"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"650","noun":"chat_conversation","acts_on":{"noun":"chat_conversation","address":"650","domain":"Website chat","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chat/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"assigned_to_user_id":{},"assignment_taken":{},"conversation_id":{},"detail":{},"error":{},"message_id":{},"sent":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chat_widget.create","description":"Create a site chat widget for this company — the on-site AI chat bubble. Returns the widget id + public chat_id. Use chat_widget_embed to get the snippet to paste on the site.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Internal widget name."},"site_id":{"type":"integer","description":"Optional site id to attach the widget to."},"agent_id":{"type":"integer","description":"Optional agent id to answer chats."},"greeting_message":{"type":"string","description":"First message the widget shows."},"personality":{"type":"string","maxLength":100},"enable_lead_capture":{"type":"boolean","description":"Default true."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"comms:write","transport":"http","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chat_widget/create","http_method":"POST","dispatch_endpoint":null},{"name":"chat_widget.embed","description":"Get the embeddable <script> snippet for a chat widget — paste it into any site's HTML to show the AI chat bubble. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","description":"ChatWidget id (from chat_widget_list)."}},"required":["widget_id"]},"required_scope":"comms:read","transport":"http","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chat_widget/embed","http_method":"POST","dispatch_endpoint":null},{"name":"chat_widget.list","description":"List this company's site chat widgets (each with its id, public chat_id, name, and active state). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","description":"Include deactivated widgets. Default false."}}},"required_scope":"comms:read","transport":"http","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chat_widget/list","http_method":"POST","dispatch_endpoint":null},{"name":"chat_widget.update","description":"Update a chat widget's configuration — name, greeting, attached agent/site, lead capture, or active state (set is_active=false to pause it). Pass only the fields to change.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","description":"ChatWidget id (from chat_widget_list)."},"name":{"type":"string","maxLength":200},"site_id":{"type":"integer"},"agent_id":{"type":"integer"},"greeting_message":{"type":"string"},"personality":{"type":"string","maxLength":100},"enable_lead_capture":{"type":"boolean"},"is_active":{"type":"boolean","description":"Set false to pause the widget."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"comms:write","transport":"http","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/chat_widget/update","http_method":"POST","dispatch_endpoint":null},{"name":"chat_widget_create","description":"Create a site chat widget for this company — the on-site AI chat bubble. Returns the widget id + public chat_id. Use chat_widget_embed to get the snippet to paste on the site.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"description":"Internal widget name."},"site_id":{"type":"integer","description":"Optional site id to attach the widget to."},"agent_id":{"type":"integer","description":"Optional agent id to answer chats."},"greeting_message":{"type":"string","description":"First message the widget shows."},"personality":{"type":"string","maxLength":100},"enable_lead_capture":{"type":"boolean","description":"Default true."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"comms:write","transport":"dispatch","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"chat_widget.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"chat_widget_embed","description":"Get the embeddable <script> snippet for a chat widget — paste it into any site's HTML to show the AI chat bubble. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","description":"ChatWidget id (from chat_widget_list)."}},"required":["widget_id"]},"required_scope":"comms:read","transport":"dispatch","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"chat_widget.embed","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"chat_widget_list","description":"List this company's site chat widgets (each with its id, public chat_id, name, and active state). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","description":"Include deactivated widgets. Default false."}}},"required_scope":"comms:read","transport":"dispatch","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"chat_widget.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"widgets":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"chat_widget_update","description":"Update a chat widget's configuration — name, greeting, attached agent/site, lead capture, or active state (set is_active=false to pause it). Pass only the fields to change.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","description":"ChatWidget id (from chat_widget_list)."},"name":{"type":"string","maxLength":200},"site_id":{"type":"integer"},"agent_id":{"type":"integer"},"greeting_message":{"type":"string"},"personality":{"type":"string","maxLength":100},"enable_lead_capture":{"type":"boolean"},"is_active":{"type":"boolean","description":"Set false to pause the widget."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"651","noun":"chat_widget","acts_on":{"noun":"chat_widget","address":"651","domain":"Website chat","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"chat_widget.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"checkout.initiate","description":"Initiate checkout — returns the full offer: line items, unit prices, tax, the merchant's fee programme and its disclosure, priced through the same engine the charge uses. Pass `channel` truthfully: a convenience fee is legal only on an alternate channel, never in person.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cart_id":{"type":"integer","minimum":1},"payment_method":{"type":"string","nullable":true},"channel":{"type":"string","enum":["online","phone","in_person","invoice"],"default":"online","description":"Where the sale is happening. Decides which fee rules apply and what the surface must display."}},"required":["cart_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"49","noun":"checkout","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/checkout/initiate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cart_id":{},"next_step":{},"offer":{},"payment_method":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"clarity.audit","description":"Run the mechanical Four-Questions audit against one page (what you sell / who it's for / what it costs / how it works). Same logic as the nightly Celery sweep, but synchronous and addressable by an agent. Persists a PageClarityAudit row.","shape":"aggregate","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"09","noun":"clarity","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/clarity/audit","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audit_id":{},"audit_version":{},"blocking_issue":{},"four_questions":{},"max_score":{},"model_used":{},"ok":{},"overall_score":{},"page_id":{},"reason":{},"site_id":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.analyze_design","description":"Extract design tokens (colors / typography / spacing / shape) from a reference image via Alex's design-analysis capability.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"image_base64":{"type":"string","nullable":true},"image_url":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/analyze-design","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message":{},"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.blog.create","description":"Create a new blog post with optional SEO metadata.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Post title"},"content":{"type":"string","description":"Post content (markdown or HTML)"},"excerpt":{"type":"string","description":"Short excerpt/summary"},"author":{"type":"string","description":"Author name (defaults to \"AI Content Team\")"},"category":{"type":"string","description":"Post category (defaults to \"general\")"},"tags":{"type":"string","description":"List of tags"},"seo_title":{"type":"string","description":"SEO title override (50-60 chars ideal)"},"seo_description":{"type":"string","description":"Meta description (150-160 chars ideal)"},"featured_image":{"type":"string","description":"URL to featured image"},"publish":{"type":"boolean","description":"If True, publish immediately"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","title"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"blog.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/blog.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"post":{},"published_url":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.blog.list","description":"Lists the tenant's blog posts (blog_posts), newest first, optionally filtered to status published or draft, with skip/limit paging. archived=true lists ONLY archived posts (restore one with blog.restore). Returns the posts and the total count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"skip":{"type":"integer","description":"Number of records to skip (pagination)"},"limit":{"type":"integer","description":"Maximum number of records to return"},"status":{"type":"string","description":"Filter by status — 'published', 'draft', or None for all"},"archived":{"type":"boolean","description":"true = list ONLY archived posts (default false: live posts)"}}},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/blog.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"limit":{},"posts":{},"skip":{},"success":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.chat","description":"Open-ended chat with Alex CMS AI. Same engine as the dashboard visual-canvas Alex panel. Pass page_id to scope the conversation to a specific page.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":4000},"page_id":{"type":"integer","minimum":1,"nullable":true},"images":{"type":"array","items":{"type":"string"},"nullable":true}},"required":["message"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/chat","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.generate_section","description":"Generate a single CMS section (hero / features / cta / etc.) via Alex AI. Returns section JSON ready to splice into a page's layout.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"section_type":{"type":"string"},"requirements":{"type":"string","minLength":1,"maxLength":2000},"existing_sections":{"type":"array","nullable":true}},"required":["requirements","section_type"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/generate-section","http_method":"POST","dispatch_endpoint":null},{"name":"cms.modify_page","description":"Modify a CMS page via Alex AI. apply_changes=False returns a preview; apply_changes=True commits the new layout_json with versioning.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"instruction":{"type":"string","minLength":1,"maxLength":4000},"apply_changes":{"type":"boolean","default":false},"images":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","instruction"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/modify-page","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"applied":{},"design_analysis":{},"ok":{},"page_id":{},"reason":{},"response":{},"sections":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.modify_section","description":"Modify a single block/section via Alex AI. Returns the modified section JSON ready to splice into layout_json.sections.","shape":"transaction","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"section":{"type":"object"},"modification_request":{"type":"string","minLength":1,"maxLength":2000}},"required":["modification_request","section"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/modify-section","http_method":"POST","dispatch_endpoint":null},{"name":"cms.page.create","description":"Creates a draft website page (website_pages) from a title, with optional slug, layout_json, page_type and site_id. Reserved or taken slugs are adjusted. Returns the new page; it is not published.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Page title"},"slug":{"type":"string","description":"URL slug (auto-generated from title if not provided)"},"description":{"type":"string","description":"Short page description"},"layout_json":{"type":"string","description":"Page layout as JSON (Sanity-style components)"},"page_type":{"type":"string","description":"Page type — website, landing, blog, booking, product, email_landing, review"},"template":{"type":"string","description":"Template name (default: \"default\")"},"site_id":{"type":"string","description":"Site ID to group page under"},"is_landing_page":{"type":"boolean","description":"If True, renders without nav/footer under /lp/ prefix"},"ai_generated":{"type":"boolean","description":"Whether this page was AI-generated"},"ai_prompt":{"type":"string","description":"Original AI prompt used to generate page"},"featured_image":{"type":"string","description":"Hero image URL"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/page.create","http_method":"POST","dispatch_endpoint":null},{"name":"cms.page.get","description":"Get a single CMS page by ID with full layout data.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"The page ID to retrieve"}},"required":["page_id"]},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/page.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"page":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.page.publish","description":"Publish a CMS page (make it live on the website).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"The page ID to publish"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.publish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/page.publish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"fidelity":{},"next":{},"reason":{},"success":{},"violations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.page.unpublish","description":"Unpublish a CMS page (remove from public website, keep as draft).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"The page ID to unpublish"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.unpublish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/page.unpublish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"page":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.page.update","description":"Update an existing CMS page. Automatically versions layout changes.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"The page ID to update"},"title":{"type":"string","description":"New page title"},"description":{"type":"string","description":"New description"},"layout_json":{"type":"string","description":"New layout JSON (previous version saved to layout_history)"},"template":{"type":"string","description":"New template name"},"featured_image":{"type":"string","description":"New featured image URL"},"page_type":{"type":"string","description":"New page type"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/page.update","http_method":"POST","dispatch_endpoint":null},{"name":"cms.pages.list","description":"Lists the tenant's website pages (website_pages), most recently updated first, filterable by published_only, page_type and site_id. Returns slug, title, publish state and show_in_nav per page.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"published_only":{"type":"boolean","description":"If True, only return published pages"},"page_type":{"type":"string","description":"Filter by page type (website, landing, blog, booking, product)"},"site_id":{"type":"string","description":"Filter by site ID"},"limit":{"type":"integer","description":"Maximum pages to return (default 50)"},"skip":{"type":"integer","description":"Number of records to skip (pagination)"}}},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":"page.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/pages.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"limit":{},"pages":{},"skip":{},"success":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.script_hosts_list","description":"The hosts this company's custom <head>/<body> code may load scripts, frames and requests from: `declared` (this company's own list) and `defaults` (the analytics/booking/video hosts every tenant gets). A bare host covers its subdomains; '*.example.com' covers subdomains only. Read this before writing custom code that loads a third-party script.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/script-hosts-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"declared":{},"defaults":{},"error":{},"note":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.script_hosts_set","description":"Add and/or remove hosts on this company's custom-code script allowlist. Each host must be a bare hostname ('cdn.example.com') or one leading wildcard ('*.example.com') — no scheme, path, port, IP address, localhost or private suffix; one bad host refuses the whole call and nothing changes. Touches only the allowlist, never other website settings. Returns declared/added/removed. Shared-hosting and public-suffix domains (github.io, vercel.app, cloudfront.net, raw IPs…) are refused: anyone can publish code there. A declared host can run code on the live site, so this needs the owner's approval (R3).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string"},"nullable":true},"remove":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_hosts","when":"A host in `add` fails validation (scheme/path/port, IP, localhost, bare public suffix, shared hosting like github.io); each refused host carries its reason and nothing changes.","override":null,"code_in_response":true},{"code":"too_many_hosts","when":"The list would exceed 50 hosts; nothing changes.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/script-hosts-set","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"added":{},"declared":{},"detail":{},"error":{},"max":{},"not_present":{},"refused":{},"removed":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.settings.update","description":"Updates a site's settings on the sites table (the primary active site unless site_id is given): config merge, meta_title, meta_description, analytics_enabled, template. Refuses domain changes. Returns the site.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"settings":{"type":"object","description":"Settings dictionary. Supported keys:"},"site_id":{"type":"string","description":"Specific site ID to update. If None, updates primary site."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["settings"]},"required_scope":"pages:write","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"domain_requires_verification","when":"settings contains `domain` — use domain.create then domain.verify.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/settings.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"settings":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms.settings_get","description":"Read this company's CMS settings — site config/theme, SEO meta, features, domain.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/settings-get","http_method":"POST","dispatch_endpoint":null},{"name":"cms.suggest","description":"Get Alex's improvement suggestions for a CMS page. Read-only — returns List[str] of suggestions.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"73","noun":"cms","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/cms/suggest","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"page_id":{},"reason":{},"suggestions":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"cms_settings_get","description":"Read this company's CMS settings — site config/theme, SEO meta, features, domain.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"pages:read","transport":"dispatch","coordinate":"73","noun":"cms","location":"svc.api","same_as":"cms.settings_get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"cms_settings_update","description":"Update this company's CMS settings. `settings` accepts: config (dict — theme/layout/features), meta_title, meta_description, analytics_enabled, template. A domain is attached with domain_add and confirmed with domain_verify. Reversible (re-set to change back).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"settings":{"type":"object","description":"Settings to update (config/meta_title/meta_description/analytics_enabled/template)."},"site_id":{"type":"integer","description":"Optional site to scope the settings to."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["settings"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"73","noun":"cms","location":"svc.api","same_as":"cms.settings.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"code.diff","description":"Show all pending changes — sandbox diffs, unpublished pages, uncommitted module changes.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"code","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/code/diff","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"diffs":{},"has_changes":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"code.history","description":"Interleaved history from all code systems — entity versions, page versions, module versions.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"code","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/code/history","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"history":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"code.rollback","description":"Unified rollback — routes to the right system (module versioning or entity versioning) based on entity_type.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"entity_type":{"type":"string","minLength":1},"entity_id":{"type":"integer","minimum":1},"version":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["entity_id","entity_type","version"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"code","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/code/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"code.status","description":"Unified status across all code systems — pages, modules, chains, nest imports, sandbox, entity history.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"code","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/code/status","http_method":"POST","dispatch_endpoint":null},{"name":"commission.preview_settlement","description":"Project a promoter/affiliate settlement over a date window.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subject_id":{"type":"string","minLength":1},"role":{"type":"string","default":"promoter"},"date_from":{"type":"string","format":"date-time"},"date_to":{"type":"string","format":"date-time"},"withholding_pct":{"type":"number","minimum":0,"maximum":100,"default":0}},"required":["subject_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"564","noun":"commission_ledger","acts_on":{"noun":"commission_ledger","address":"564","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/commission/preview-settlement","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"counts":{},"currency":{},"error":{},"error_code":{},"reasons":{},"role":{},"subject_id":{},"success":{},"totals":{},"verdict":{},"window":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.enable_recipe","description":"One-click enable a starter automation recipe by key. THIS is the consent moment (standing-plan model): once enabled, matching call events fire the actions without re-prompting — governed by quiet hours, TCPA/DNC, and fraud caps below the verbs.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"recipe_key":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["recipe_key"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/enable-recipe","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"enabled":{},"error":{},"name":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.history","description":"A workflow's recent fire receipts — exactly what the AI did, when, to whom (every fire is receipted).","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1}},"required":["workflow_id"],"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/history","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"fire_count":{},"name":{},"receipts":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.list","description":"The company's comms automations + the 6 starter recipes (missed-call text-back, voicemail text-back, quote follow-up, sentiment guard, callback promise keeper, booking confirmation) with installed state. A workflow = a saved, event-triggered verb chain: call events (outcome_tag, missed, negative sentiment, voicemail) fire actions like sms.send / email.send.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"recipes":{},"workflows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.remove","description":"Remove an automation entirely, rather than pausing it. set_enabled(False) leaves the row in place, which reads as a half-on thing nobody wanted; this is the answer to 'I don't want this at all'. ⚠️ DELETES the fire receipts with it — the record of what the AI sent in this company's name — so the answer reports fire_count and receipts_discarded. Pause instead if the history matters. A starter recipe can be re-created later with enable_recipe, but the receipts and any edited wording do not come back.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["workflow_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/remove","http_method":"POST","dispatch_endpoint":null},{"name":"comms_workflow.set_copy","description":"Reword what an automation sends, in this company's own voice. Every recipe ships one sentence written for nobody in particular; until this verb, every tenant sent identical words. COPY ONLY — `to` and `verb` are not editable, so a wording change can never re-point automation past the quiet-hours, TCPA and consent gates. Use {{business_name}} / {{caller}}; an unknown placeholder is refused rather than stored, because it would reach the customer as literal braces.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"message":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["workflow_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"empty_copy","when":"A message, subject or body is blank.","override":null,"code_in_response":true},{"code":"unknown_placeholder","when":"The text uses a {{token}} that cannot be rendered.","override":null,"code_in_response":true},{"code":"field_not_on_this_workflow","when":"No action in the workflow has that field (SMS has message; email has subject/body).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/set-copy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"actions":{},"detail":{},"error":{},"updated":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.set_enabled","description":"Activate or pause a comms automation workflow.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"enabled":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["workflow_id","enabled"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/set-enabled","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"enabled":{},"error":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"comms_workflow.test_fire","description":"Dry-run a workflow against a synthetic matching event — returns exactly what it WOULD do (rendered args, quiet-hour suppressions). Nothing sends.","shape":"preview","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"caller":{"type":"string","default":"+15555550100","pattern":"^\\+?[0-9]{7,15}$"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["workflow_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"671","noun":"comms_workflow","acts_on":{"noun":"comms_workflow","address":"671","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/comms_workflow/test-fire","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"receipt":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"communication.toggle","description":"Turns one channel master switch (email, sms, voice, chat, web_push, slack, teams) on or off in communication_settings. Returns the stored value and all channel states.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"channel":{"type":"string","minLength":1},"enabled":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["channel","enabled"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"672","noun":"communication_settings","acts_on":{"noun":"communication_settings","address":"672","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/communication/toggle","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"channel":{},"channels":{},"enabled":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"communication.update_settings","description":"Updates this company's communication_settings row using flat field names (email_enabled, quiet_hours_start HH:MM, ...). Lead email routing: lead_alert_emails (list; replaces the owner/admin recipients of new-lead emails), lead_alert_cc (list; copied), lead_submitter_copy (bool; emails the visitor a copy of what they sent) — a bad address is returned under invalid. Returns which keys were applied or ignored plus the saved settings.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"settings":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["settings"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"672","noun":"communication_settings","acts_on":{"noun":"communication_settings","address":"672","domain":"Campaigns, automations & channel rules","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/communication/update-settings","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"applied":{},"ignored":{},"invalid":{},"settings":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"company.add_money_function","description":"Add a money function this company's industry did not give it (a florist who quotes weddings adds `estimate`), or remove one it ADDED. Industry defaults cannot be removed. Functions: shop_pos, estimate, invoice, custom_order, treatment_plan.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string","enum":["shop_pos","estimate","invoice","custom_order","treatment_plan"]}},"remove":{"type":"array","items":{"type":"string","enum":["shop_pos","estimate","invoice","custom_order","treatment_plan"]}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"company:write","transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/add-money-function","http_method":"POST","dispatch_endpoint":null},{"name":"company.capabilities","description":"What is actually wired for this tenant and what is not: brand tokens, a reachable public address, published pages, and the asset store. Every entry says WHY it is not ready and what to run. Start here when a site looks wrong or something is not working.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/capabilities","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"company.check_feature","description":"Company — read whether a feature key is enabled in this company's feature_settings. Read-only; returns enabled=false with a reason if the company is missing.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"feature_key":{"type":"string"}},"required":["feature_key"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/check-feature","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"enabled":{},"feature_key":{},"reason":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"company.create_field_schema","description":"Company — define a custom CRM field on an entity type (writes company_field_schemas). Distinct from field.create, which writes the field manual.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"entity_type":{"type":"string","description":"contact, customer, deal, lead, ..."},"field_name":{"type":"string"},"field_type":{"type":"string","default":"text","enum":["text","number","date","datetime","select","multi_select","boolean","email","phone","url"]},"field_label":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["entity_type","field_name"],"additionalProperties":true},"required_scope":"company:write","transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/create-field-schema","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"entity_type":{},"field_key":{},"field_label":{},"field_schema_id":{},"field_type":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"company.money_functions","description":"How this business takes money — shop_pos, estimate, invoice, custom_order, treatment_plan. Its industry (kb_sub_code) decides the defaults; the owner can add more. Returns `functions` (what it has) and every function's state: default (fixed), added (removable) or available, plus `suggested`. Read this before offering an estimate, a POS sale or a treatment plan.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/money-functions","http_method":"POST","dispatch_endpoint":null},{"name":"company.update_profile","description":"Company — update name, public contact email (contact_email; \"\" clears it), phone (contact_phone), address (location) or industry. `website` has no column on companies and always raises — a web address is a Site or a custom domain.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"nullable":true,"type":"string"},"email":{"nullable":true,"type":"string","description":"Public contact email shown on the site footer and in status. Empty string clears it; otherwise must be a valid address."},"phone":{"nullable":true,"type":"string"},"address":{"nullable":true,"type":"string"},"industry":{"nullable":true,"type":"string"},"website":{"nullable":true,"type":"string","description":"Not supported — raises. Use site.create / domain.create."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"company:write","transport":"http","coordinate":"22","noun":"company","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/company/update-profile","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"compliance.check_location","description":"Is a fee program legal WHERE THIS SALE HAPPENS? The law follows the sale, not the headquarters — a Utah company taking payment at its Connecticut counter is bound by Connecticut, where surcharging is banned. Returns the governing state, the ZIP, which field it came from, the MCC class, and everything a human must resolve first. Call it per location.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/compliance/check-location","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"confident":{},"location_id":{},"mcc":{},"mcc_class":{},"mcc_note":{},"must_resolve":{},"postal_code":{},"programs":{},"resolved_from":{},"sales_tax_treatment":{},"source":{},"state":{},"verified_at":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"compliance.fee_law_drift","description":"Which jurisdictions in the fee-law map are stale or flagged for a human. Deterministic, no AI call — run this before researching.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"state":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/compliance/fee-law-drift","http_method":"POST","dispatch_endpoint":null},{"name":"compliance.fee_programs","description":"What fee programs are legal where this merchant operates — surcharge, dual pricing, cash discount, convenience fee — with the state cap, the display and notice duties, the sales-tax position, and whether the jurisdiction needs legal review. Ask before enabling anything.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"state":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/compliance/fee-programs","http_method":"POST","dispatch_endpoint":null},{"name":"compliance.merchant_profile","description":"The whole fee picture for a merchant: the state resolved from their ZIP, what each program is legally allowed to do there, the cost of acceptance from their MCC, the per-brand surcharge caps, what the connected processor can execute, and which program to actually run with the trade-off named. Onboarding and settings both read this, so they cannot disagree. Safe before a processor is connected.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/compliance/merchant-profile","http_method":"POST","dispatch_endpoint":null},{"name":"compliance.research_fee_law","description":"Ask the AI to re-read one state's fee law and diff it against the map. PROPOSES ONLY — returns differences and citations for a human to accept; never edits the rules file. Findings without a citation are discarded.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"state":{"type":"string","minLength":2,"maxLength":2}},"required":["state"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/compliance/research-fee-law","http_method":"POST","dispatch_endpoint":null},{"name":"connect_thumbtack","description":"Start connecting this company's Thumbtack account. Returns an authorization URL the business owner opens to grant access; once authorized, Thumbtack leads flow into the CRM. Read-only (no changes until the owner completes the authorization).","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"99","noun":"connect","location":"svc.api","same_as":"thumbtack.connect","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"authorization_url":{},"next_step":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"console.approve_sandbox","description":"Approve a sandbox file and promote it to live — NOT implemented; always raises. No code path publishes an approved file; the REST handler only sets a status column.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"06","noun":"console","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/console/approve-sandbox","http_method":"POST","dispatch_endpoint":null},{"name":"console.end_session","description":"End an active console session. Really ends it; the session is proved to belong to the calling tenant first.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"session_token":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["session_token"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"06","noun":"console","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/console/end-session","http_method":"POST","dispatch_endpoint":null},{"name":"console.reject_sandbox","description":"Reject a sandbox file so it is never published. Really writes the row, scoped to the calling tenant. Does not delete the file.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"06","noun":"console","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_rejected","when":"The sandbox file was already rejected; nothing changes.","override":null,"code_in_response":false}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/console/reject-sandbox","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"file_id":{},"file_name":{},"note":{},"previous_status":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"console.rollback_file","description":"Roll a console file back to a previous version — NOT implemented; always raises. Restore from console_file_history has never been built; the REST endpoint returns the same fictional receipt.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"06","noun":"console","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/console/rollback-file","http_method":"POST","dispatch_endpoint":null},{"name":"console.start_session","description":"Start a console/sandbox session. Really creates the session and returns a usable session_token.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"06","noun":"console","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/console/start-session","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"session_status":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.add_note","description":"Adds a note to a CRM contact (crm_contact_notes, for a crm_contacts id) with optional title, type and pin. Requires contact_id and content; returns the new note_id, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"content":{"type":"string","minLength":1},"note_type":{"type":"string","default":"general"},"title":{"type":"string","nullable":true},"is_pinned":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","content"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/add-note","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"note_id":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.assign_agent","description":"Sets which AI agent owns a CRM contact (crm_contacts.assigned_to_agent, stamps assigned_at). Requires contact_id and agent_type; returns status assigned, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"agent_type":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","agent_type"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/assign-agent","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_type":{},"contact_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.configure_automation","description":"Configure automation settings for a CRM contact.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"automation_settings":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","automation_settings"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/configure-automation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"automation_settings":{},"contact_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.create","description":"Creates a person in the tenant CRM (crm_contacts) from one name string plus phone and/or email; refuses placeholder names like N/A. Returns the new contact_id, or status exists with the matching id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company_name":{"type":"string","nullable":true},"source":{"type":"string","default":"agent"},"contact_type":{"type":"string","nullable":true},"custom_fields":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":"crm.contacts.create","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.relationship_map","description":"Contact + CrmCompany + peers + deals + activities.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1}},"required":["contact_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/relationship-map","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"activities":{},"contact":{},"crm_company":{},"deals":{},"error":{},"error_code":{},"peer_contacts":{},"peer_count":{},"success":{},"totals":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"contact.set_bucket","description":"Who a person is to the business: file them as customer, lead, contact or vendor (crm_contacts.bucket — the platform bucket under the trade's word, e.g. a clinic's 'patient' is a customer). By contact_id, or by email / phone — finds this company's person or creates them in that bucket (the inbox's 'file the sender'). Writes the move and its reason on their timeline and emits crm.contact.bucket_changed. dry_run=true returns from/to and what would fire without writing. A lead becomes a customer by itself on a signed estimate, a paid invoice or a won deal.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"bucket":{"type":"string","enum":["customer","lead","contact","vendor"]},"contact_id":{"type":"integer","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"name":{"type":"string","nullable":true,"description":"for a new person"},"reason":{"type":"string","nullable":true,"description":"shown on their timeline"},"dry_run":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["bucket"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/set-bucket","http_method":"POST","dispatch_endpoint":null},{"name":"contact.set_consent","description":"Record a contact's communication consent for a channel (voice / sms / email), WITH provenance — the audited, lawful path to enable AI outreach to that contact. `basis` says how consent was obtained: 'web_form' (written), 'verbal_inbound' (they called/opted in), or 'operator_attested' (you attest a known relationship, e.g. the owner's own number). IMPORTANT: operator_attested is a WEAKER basis for transactional / informational contact only — it is NOT accepted for marketing consent, which requires written (web_form) consent under TCPA.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id to record consent for."},"channel":{"type":"string","enum":["voice","sms","email"],"description":"Communication channel this consent covers."},"basis":{"type":"string","enum":["web_form","verbal_inbound","operator_attested"],"description":"How the consent was obtained (its lawful basis + provenance source)."},"consent_level":{"type":"string","enum":["transactional","marketing"],"description":"transactional (informational — reminders/confirmations) or marketing. Default transactional."},"disclosure_text":{"type":"string","description":"Optional — the exact language the contact saw/agreed to (stored as proof)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","channel","basis"]},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/set-consent","http_method":"POST","dispatch_endpoint":null},{"name":"contact.suggest_nurture_sequence","description":"Recommend a 3-step follow-up cadence (hot, warm or cold) for a CRM contact (crm_contacts) by contact_id, based on days since their last activity. Read-only; returns the steps, channel and a confidence score.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1}},"required":["contact_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/suggest-nurture-sequence","http_method":"POST","dispatch_endpoint":null},{"name":"contact.update","description":"Update an existing CRM contact's fields.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"company_name":{"type":"string","nullable":true},"contact_type":{"type":"string","nullable":true},"custom_fields":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"31","noun":"contact","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contact/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.ace.generate_blog","description":"Generate SEO-optimized blog post for company website.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Blog post title"},"keywords":{"type":"array","description":"SEO keywords to include (e.g., [\"AI agents\", \"automation\"])"},"word_count":{"type":"integer","description":"Target word count (default: 1000)"},"outline":{"type":"string","description":"Optional outline/structure for the post"},"publish_immediately":{"type":"boolean","description":"If True, creates BlogPost record and publishes to website"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["keywords","title"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/ace.generate-blog","http_method":"POST","dispatch_endpoint":null},{"name":"content.ace.generate_product_desc","description":"Generate AI-powered product description.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Product ID to generate description for"},"description_type":{"type":"string","description":"Type (full, short, feature_list, benefits)"},"tone":{"type":"string","description":"Optional tone override"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/ace.generate-product-desc","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"content":{},"error":{},"generation_time_ms":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.ace.list_blogs","description":"List blog posts for the company website.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"published_only":{"type":"boolean","description":"Only show published posts (default: True)"},"limit":{"type":"integer","description":"Maximum posts to return"}}},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/ace.list-blogs","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"blog_posts":{},"error":{},"success":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.ace.publish_blog","description":"Publish a draft blog post to the website.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"Blog post ID to publish"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/ace.publish-blog","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"live_url":{},"message":{},"published_url":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.ace.unpublish_blog","description":"Unpublish a blog post (convert to draft).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blog_post_id":{"type":"integer","description":"Blog post ID to unpublish"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["blog_post_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/ace.unpublish-blog","http_method":"POST","dispatch_endpoint":null},{"name":"content.generate_ad","description":"AI-generate ad copy variations for a platform.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"product_id":{"type":"integer","nullable":true},"keywords":{"type":"array","items":{"type":"string"},"nullable":true},"variations":{"type":"integer","minimum":1,"maximum":10,"default":3},"agent_name":{"type":"string","default":"marcus"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/generate-ad","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.generate_and_review","description":"Full content pipeline: generate → AI review → revise (up to 3x) → approve.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content_type":{"type":"string","description":"Type — blog_post, email"},"title":{"type":"string","description":"Content title (required for blog_post)"},"keywords":{"type":"string","description":"SEO keywords (for blog_post)"},"word_count":{"type":"integer","description":"Target word count (for blog_post)"},"outline":{"type":"string","description":"Content outline/structure"},"agent_type":{"type":"string","description":"Agent type to generate content — \"developer\", \"marketing\", \"brand\""},"publish_immediately":{"type":"boolean","description":"If True, publish after approval"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/generate-and-review","http_method":"POST","dispatch_endpoint":null},{"name":"content.generate_blog","description":"AI-generate a blog post. Optionally auto-publish.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"keywords":{"type":"array","items":{"type":"string"},"nullable":true},"word_count":{"type":"integer","minimum":100,"maximum":5000,"default":800},"outline":{"type":"string","nullable":true},"publish_immediately":{"type":"boolean","default":false},"agent_name":{"type":"string","default":"marcus"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/generate-blog","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.generate_email","description":"AI-drafts email campaign copy (subject, body, CTA) in the tenant's brand voice for a campaign type, audience and message; saves it as a content template. Needs brand voice settings.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_type":{"type":"string","minLength":1},"audience":{"type":"string","minLength":1},"message":{"type":"string","minLength":1},"tone":{"type":"string","default":"professional"},"subject_line":{"type":"string","nullable":true},"agent_name":{"type":"string","default":"marcus"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["audience","campaign_type","message"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/generate-email","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.generate_social","description":"AI-generate a social media post for a platform.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"topic":{"type":"string","minLength":1},"hashtags":{"type":"boolean","default":true},"emojis":{"type":"boolean","default":true},"agent_name":{"type":"string","default":"marcus"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","topic"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/generate-social","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.marcus.generate_ad","description":"Generate ad copy variations for A/B testing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","description":"Advertising platform (google_ads, facebook_ads, linkedin_ads)"},"keywords":{"type":"array","description":"List of ad keywords/targeting terms"},"product_id":{"type":"string","description":"Optional product ID to reference"},"variations":{"type":"integer","description":"Number of variations to generate (default: 3)"},"save_as_template":{"type":"boolean","description":"Save generated variations as templates"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["keywords","platform"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/marcus.generate-ad","http_method":"POST","dispatch_endpoint":null},{"name":"content.marcus.generate_email","description":"Marcus drafts email campaign copy (subject, body, CTA) in the tenant's brand voice for a campaign type, audience and message, optionally saving it to content_templates. Needs brand voice settings.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_type":{"type":"string","description":"Type of campaign (welcome, promotional, newsletter, follow_up)"},"audience":{"type":"string","description":"Target audience description (e.g., \"Tech professionals aged 30-50\")"},"message":{"type":"string","description":"Core message to communicate (e.g., \"Announcing new AI feature\")"},"tone":{"type":"string","description":"Optional tone override (professional, casual, urgent, friendly)"},"save_as_template":{"type":"boolean","description":"Save generated content as reusable template"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["audience","campaign_type","message"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/marcus.generate-email","http_method":"POST","dispatch_endpoint":null},{"name":"content.marcus.list_templates","description":"List saved content templates with performance metrics.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_type":{"type":"string","description":"Filter by type (email_campaign, social_post, ad_copy, blog_post)"},"min_performance_score":{"type":"string","description":"Only show templates above this score (0-100)"},"limit":{"type":"integer","description":"Maximum templates to return"}}},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/marcus.list-templates","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"templates":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.marcus.use_template","description":"Retrieve and use an existing content template.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"integer","description":"Template ID to retrieve"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["template_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/marcus.use-template","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"template":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.maya.generate_social","description":"Maya drafts a social post for a platform and topic in the tenant's brand voice (hashtags, emoji per brand setting) and can save it as a content template. Needs brand voice settings.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","description":"Platform (facebook, instagram, linkedin, twitter)"},"topic":{"type":"string","description":"Topic or message to post about"},"hashtags":{"type":"boolean","description":"Include relevant hashtags (default: True)"},"emojis":{"type":"string","description":"Use emojis (None = use brand voice setting)"},"save_as_template":{"type":"boolean","description":"Save as reusable template"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","topic"]},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/maya.generate-social","http_method":"POST","dispatch_endpoint":null},{"name":"content.maya.list_social_templates","description":"List the tenant's active social_post templates from content_templates, best performance score first; optional platform and min_performance_score filters. Returns id, name, platform, score, times_used, preview.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","description":"Filter by platform (facebook, instagram, linkedin, twitter)"},"min_performance_score":{"type":"string","description":"Only show templates above this score"},"limit":{"type":"integer","description":"Maximum templates to return"}}},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/maya.list-social-templates","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"templates":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.maya.update_brand_voice","description":"Update the tenant's brand_voice_settings row (tone, personality, emoji use, preferred and forbidden words, target audience); only fields passed change. Fails if no brand voice row exists yet.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tone":{"type":"string","description":"Brand tone (professional, casual, friendly, luxury, etc.)"},"brand_personality":{"type":"string","description":"List of personality traits"},"use_emojis":{"type":"string","description":"Whether to use emojis in social content"},"preferred_keywords":{"type":"string","description":"Keywords to emphasize"},"forbidden_words":{"type":"string","description":"Words to avoid"},"target_audience":{"type":"string","description":"Updated audience description"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"marketing:write","transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/maya.update-brand-voice","http_method":"POST","dispatch_endpoint":null},{"name":"content.review.list","description":"List content review workflows for a company.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Filter by status — pending, approved, rejected, revision_requested"},"content_type":{"type":"string","description":"Filter by content type — blog_post, email, social_post, page"},"limit":{"type":"integer","description":"Maximum records to return"},"skip":{"type":"integer","description":"Number of records to skip"}}},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/review.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"limit":{},"skip":{},"success":{},"total":{},"workflows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.review.status","description":"Check the status of a content review workflow.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","description":"The ContentApprovalWorkflow ID"}},"required":["workflow_id"]},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/review.status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"workflow":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"content.review.submit","description":"Submit content for AI brand voice review.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","description":"The content text to review"},"content_type":{"type":"string","description":"Type — blog_post, email, social_post, page"},"content_id":{"type":"string","description":"Optional ID of the content record (for audit trail)"},"generated_by_agent_id":{"type":"string","description":"ID of the agent that generated the content"}},"required":["content"]},"required_scope":null,"transport":"http","coordinate":"95","noun":"content","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/content/review.submit","http_method":"POST","dispatch_endpoint":null},{"name":"contract.add_term","description":"Add one commercial term to a vendor contract — fee type, basis, rate or amount, scope, effective dates — with the contract's own words (excerpt) and page. Lands proposed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contract_id":{"type":"integer","minimum":1},"fee_type":{"type":"string","description":"A key of the fee taxonomy (constants/vendor_fee_taxonomy.py), e.g. processor_markup, authorization_fee, pci_compliance_fee, credit."},"basis":{"type":"string","enum":["percent_of_volume","per_item","fixed_per_period","pass_through","credit"]},"excerpt":{"type":"string","minLength":1,"description":"The contract's own words this term comes from."},"label":{"type":"string"},"rate_bps":{"type":"number","minimum":0,"description":"Basis points: 0.25% = 25."},"amount":{"type":"number","minimum":0,"description":"Dollars: per item, per period, or the credit."},"min_amount":{"type":"number","minimum":0},"max_amount":{"type":"number","minimum":0},"merchant_id":{"type":"string"},"location":{"type":"string"},"effective_from":{"type":"string","description":"YYYY-MM-DD"},"effective_to":{"type":"string","description":"YYYY-MM-DD"},"page":{"type":"integer","minimum":1},"section":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contract_id","fee_type","basis","excerpt"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"missing_excerpt","when":"The term has no excerpt — every term must carry the contract's own words.","override":null,"code_in_response":true},{"code":"invalid_fee_type","when":"fee_type is not a key of constants/vendor_fee_taxonomy.py.","override":null,"code_in_response":true},{"code":"missing_rate_bps","when":"basis is percent_of_volume and no rate_bps was given.","override":null,"code_in_response":true},{"code":"missing_amount","when":"basis is per_item, fixed_per_period or credit and no amount was given.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/add-term","http_method":"POST","dispatch_endpoint":null},{"name":"contract.create","description":"File a vendor or processor contract (master agreement, pricing exhibit, amendment, order form …). Pass intake_id from document.extract on a page it classified `contract` and the vendor, dates, renewal, notice, ETF and every commercial term with its page and words come off the read; anything you pass overrides. parent_contract_id makes it an amendment (precedence defaults to the parent's + 10). Every term lands PROPOSED — reconciliation uses approved terms only (contract.review_term).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"vendor_id":{"type":"integer","minimum":1},"vendor_name":{"type":"string"},"title":{"type":"string"},"kind":{"type":"string","enum":["master","pricing_exhibit","amendment","order_form","program_guide","side_letter","terms_and_conditions","other"]},"parent_contract_id":{"type":"integer","minimum":1},"precedence":{"type":"integer"},"signed_date":{"type":"string"},"effective_date":{"type":"string"},"end_date":{"type":"string"},"auto_renew":{"type":"boolean"},"renewal_term_months":{"type":"integer","minimum":0},"notice_days":{"type":"integer","minimum":0},"etf_text":{"type":"string"},"etf_amount":{"type":"number","minimum":0},"merchant_ids":{"type":"array","items":{"type":"string"}},"terms":{"type":"array","items":{"type":"object"},"description":"[{fee_type, basis, excerpt, rate_bps|amount, page, …}] — added as proposed."},"document_id":{"type":"integer","minimum":1},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"wrong_document_type","when":"intake_id names a read the OCR classified as something other than a contract.","override":null,"code_in_response":true},{"code":"read_already_filed","when":"That read was already filed (as a contract, statement or anything else).","override":null,"code_in_response":true},{"code":"read_has_no_contract","when":"The read carries no contract detail; read the file again with document.extract.","override":null,"code_in_response":true},{"code":"vendor_mismatch","when":"parent_contract_id belongs to a different vendor than this contract.","override":null,"code_in_response":true},{"code":"missing_excerpt","when":"A term passed in `terms` has no excerpt. OCR terms without one are skipped and listed in terms_skipped instead.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/create","http_method":"POST","dispatch_endpoint":null},{"name":"contract.deadlines","description":"Vendor contracts ending or reaching their notice date within a window (default 120 days): end date, the last day notice can be given, auto-renewal, renewal term and ETF. Contracts with no end date on file are listed separately.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"within_days":{"type":"integer","minimum":1,"maximum":3650,"default":120},"as_of":{"type":"string","description":"YYYY-MM-DD; default today"}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/deadlines","http_method":"POST","dispatch_endpoint":null},{"name":"contract.get","description":"One vendor contract: dates, renewal, notice, ETF, every term with its citation (page, section, the contract's words), review state, and the amendment family it belongs to.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contract_id":{"type":"integer","minimum":1}},"required":["contract_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/get","http_method":"POST","dispatch_endpoint":null},{"name":"contract.list","description":"Vendor contracts on file, newest first, with how many terms are proposed, approved and rejected.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"status":{"type":"string","enum":["draft","active","expired","terminated"]},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/list","http_method":"POST","dispatch_endpoint":null},{"name":"contract.review_term","description":"A person's decision on one contract term: approve (optionally with corrections — rate, amount, dates, scope — recorded before → after) or reject. Only approved terms are used by statement.reconcile.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"term_id":{"type":"integer","minimum":1},"decision":{"type":"string","enum":["approve","reject"]},"note":{"type":"string"},"corrections":{"type":"object","description":"Fields to correct before approving."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["term_id","decision"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"523","noun":"vendor_contract","acts_on":{"noun":"vendor_contract","address":"523","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_correctable","when":"corrections names a field other than fee_type, label, basis, rate_bps, amount, min/max, scope or effective dates.","override":null,"code_in_response":true},{"code":"missing_rate_bps","when":"A correction leaves a percent-of-volume term without a rate.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/contract/review-term","http_method":"POST","dispatch_endpoint":null},{"name":"crm.activity.log","description":"Log a manual activity (call, meeting, note, etc.).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"occurred_at":{"type":"string","description":"When activity occurred (ISO format, defaults to now)"},"contact_id":{"type":"integer","description":"Contact ID"},"activity_type":{"type":"string","enum":["note","call","sms","email","webhook","meeting","system"],"description":"Type of activity (required)"},"summary":{"type":"string","description":"Activity summary (required)"},"details":{"type":"string","description":"Detailed notes"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["activity_type","summary"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/activity.log","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"activity_id":{},"contact_id":{},"created_at":{},"summary":{},"type":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.communication.stats","description":"Get communication statistics and engagement metrics.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Optional contact filter"},"deal_id":{"type":"integer","description":"Optional deal filter"},"days":{"type":"string","description":"Number of days to analyze (default 30)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/communication.stats","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_response_hours":{},"channel_breakdown":{},"inbound_count":{},"most_active_channel":{},"outbound_count":{},"period_days":{},"response_rate_percent":{},"total_messages":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.communication.suggest_follow_ups","description":"AI suggestion: Identify contacts that need follow-up communication.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days_threshold":{"type":"string","description":"Days without communication (default 14)"},"limit":{"type":"integer","description":"Max suggestions"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/communication.suggest-follow-ups","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"days_threshold":{},"follow_up_suggestions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.contacts.create","description":"Create a new contact in the CRM. Needs a phone or email; a contact with the same phone or email is returned instead of duplicated.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"first_name":{"type":"string","description":"First name (required)"},"last_name":{"type":"string","description":"Last name"},"email":{"type":"string","description":"Email address (this or phone is required)"},"phone":{"type":"string","description":"Phone number, normalized to E.164 (this or email is required)"},"voice_consent_status":{"type":"string","enum":["pending","granted"],"description":"'granted' only when the person gave verbal consent. Default 'pending'."},"tags":{"type":"array","description":"List of tags"},"source":{"type":"string","description":"Lead source"},"bucket":{"type":"string","enum":["customer","lead","contact","vendor"],"description":"Who they are to the business (default contact)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["first_name"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"created_at":{},"email":{},"full_name":{},"id":{},"message":{},"phone":{},"status":{},"voice_consent_status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.contacts.enrichment_suggest","description":"AI suggestion: Analyze contacts that need enrichment or follow-up.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max contacts to analyze"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.enrichment-suggest","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contacts_needing_attention":{},"count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.contacts.get","description":"Get detailed contact information including relationships.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID"},"include_timeline":{"type":"string","description":"Include activity timeline (default false)"}},"required":["contact_id"]},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.get","http_method":"POST","dispatch_endpoint":null},{"name":"crm.contacts.search","description":"Search contacts with filters and pagination. Filter by bucket (who they are to the business: customer, lead, contact, vendor — comma-separated) or leave some out with exclude_bucket. Each row carries bucket and stage (their furthest open deal); counts gives one number per bucket over the same search.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search term for name/email/phone"},"tags":{"type":"string","description":"Comma-separated tags to filter by"},"source":{"type":"string","description":"Contact source (website, referral, etc.)"},"bucket":{"type":"string","description":"customer | lead | contact | vendor (comma-separated for several)"},"exclude_bucket":{"type":"string","description":"buckets to leave out, e.g. vendor for a bid"},"limit":{"type":"integer","description":"Max results (default 50)"},"offset":{"type":"integer","description":"Pagination offset"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.search","http_method":"POST","dispatch_endpoint":null},{"name":"crm.contacts.tag_add","description":"Add comma-separated tags to a CRM contact (crm_contacts.tags, tenant_company_id scoped); requires contact_id and tags. Existing tags are kept and de-duplicated; returns the contact_id and full tag list.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID (required)"},"tags":{"type":["string","array"],"items":{"type":"string"},"description":"Tags to add: a list, or one comma-separated string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","tags"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.tag-add","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"tags":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.contacts.tag_remove","description":"Remove comma-separated tags from a CRM contact's crm_contacts.tags; requires contact_id and tags. Tags not present are ignored; returns the contact_id and remaining tag list.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID (required)"},"tags":{"type":["string","array"],"items":{"type":"string"},"description":"Tags to remove: a list, or one comma-separated string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","tags"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.tag-remove","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"tags":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.contacts.update","description":"Overwrite first_name, last_name, email and/or phone on a CRM contact (crm_contacts row scoped by tenant_company_id); requires contact_id. Returns id, full_name, email and phone.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID (required)"},"first_name":{"type":"string","description":"First name"},"last_name":{"type":"string","description":"Last name"},"email":{"type":"string","description":"Email address"},"phone":{"type":"string","description":"Phone number"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","email","first_name","last_name","phone"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":"contact.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/contacts.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"email":{},"full_name":{},"id":{},"phone":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.context_get","description":"Get recent CRM activity for a contact so the dispatched agent has full context before reaching out: last few calls/SMS, open deals, open tasks. Read-only. Use before voice_outbound_call to brief the call.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact ID owned by this company."}},"required":["contact_id"]},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/context-get","http_method":"POST","dispatch_endpoint":null},{"name":"crm.deals.at_risk","description":"Identify deals at risk of being lost (AI analysis).","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max deals to return"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.at-risk","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"at_risk_count":{},"deals":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.close","description":"Close a deal as Won or Lost with reason.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"Deal ID (required)"},"status":{"type":"string","description":"\"won\" or \"lost\" (required)"},"reason":{"type":"string","description":"Reason for outcome (optional)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","status"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":"deal.close","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.close","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"close_reason":{},"id":{},"stage":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.create","description":"Create a pipeline deal in crm_deals; requires title, optional stage (normalized to a canonical stage, default New), amount in dollars and contact_id. Emits crm.deal.created, logs an activity, returns the deal.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount":{"type":"string","description":"Deal value in dollars"},"title":{"type":"string","description":"Deal title (required)"},"stage":{"type":"string","description":"Initial stage (default: New)"},"contact_id":{"type":"integer","description":"Associated contact ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":"deal.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"created_at":{},"id":{},"stage":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.forecast","description":"Weighted forecast over the tenant's open crm_deals (New 10%, Qualified 30%, Proposal 50%, Negotiation 75%); fixed weights, not AI, timeframe_days is echoed only. Returns totals, top 20 deals, stage breakdown.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"timeframe_days":{"type":"string","description":"Forecast period (default 30)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.forecast","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deal_count":{},"deals":{},"forecast_period_days":{},"stage_breakdown":{},"total_pipeline_value":{},"weighted_forecast":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.get","description":"Get detailed deal information including history.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"Deal ID (required)"}},"required":["deal_id"]},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"activities":{},"amount":{},"close_reason":{},"company_id":{},"contact":{},"created_at":{},"id":{},"stage":{},"tasks":{},"title":{},"updated_at":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.list","description":"List deals with filtering and pipeline view.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"stage":{"type":"string","description":"Filter by stage (New, Qualified, Proposal, Negotiation, Won, Lost)"},"contact_id":{"type":"integer","description":"Filter by contact"},"min_amount":{"type":"string","description":"Minimum deal value in dollars"},"max_amount":{"type":"string","description":"Maximum deal value in dollars"},"limit":{"type":"integer","description":"Max results (default 50)"},"offset":{"type":"integer","description":"Pagination offset"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deals":{},"limit":{},"offset":{},"pipeline_summary":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals.update_stage","description":"Move deal to a different pipeline stage.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"Deal ID (required)"},"stage":{"type":"string","description":"New stage (required)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","stage"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals.update-stage","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"id":{},"previous_stage":{},"stage":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.deals_follow_up","description":"Create a follow-up task for EVERY deal in a stage — for example all deals still in 'New' — with ONE confirmation for the whole batch. Use when the owner says yes to following up on a group of deals, such as the next step in their report. Deals that already have an open follow-up task are skipped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"stage":{"type":"string","description":"Deal stage to follow up, e.g. 'New' (case-insensitive)."},"created_within_days":{"type":"integer","description":"Only deals created in the last N days. Default 30."},"due_in_days":{"type":"integer","description":"Tasks are due this many days from now. Default 1."},"priority":{"type":"string","enum":["low","medium","high"],"description":"Priority. Default 'medium'."},"max_deals":{"type":"integer","description":"Safety cap on how many deals to follow up. Default 50, max 200."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["stage"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/deals-follow-up","http_method":"POST","dispatch_endpoint":null},{"name":"crm.explain_contact_state","description":"Return the causal chain that produced this contact's current state.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"activity_limit":{"type":"integer","minimum":1,"maximum":100,"default":25}},"required":["contact_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/explain-contact-state","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact":{},"error":{},"error_code":{},"factors":{},"narrative":{},"recent_activity":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.leads_promote","description":"Promote a lead_submission to a real CRM contact. Use when crm_contacts_search returned a hit in the `leads` list (a lead form was submitted but never turned into a contact). Copies the lead's name/email/phone onto a new Contact row and back-links lead.contact_id so it won't show as unpromoted again. Returns a confirmation card — the promote does NOT happen until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","description":"ID of the LeadSubmission to promote."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["lead_id"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_promoted","when":"The lead already has a contact; returns that contact_id as success, nothing new is created.","override":null,"code_in_response":true},{"code":"lead_empty","when":"The lead has no name, email or phone to copy.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/leads-promote","http_method":"POST","dispatch_endpoint":null},{"name":"crm.list_recent_activity","description":"Unified recent-activity timeline for a contact.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":200,"default":25},"include_messages":{"type":"boolean","default":true}},"required":["contact_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/list-recent-activity","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"count":{},"error":{},"error_code":{},"items":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.matching.duplicates","description":"Check for potential duplicate contacts detected by AI.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max duplicates to return (default 10)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/matching.duplicates","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message":{},"potential_duplicates":{},"total_found":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.matching.explain","description":"Explain why an order is or isn't linked to a contact.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","description":"Order ID to explain"}},"required":["order_id"]},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/matching.explain","http_method":"POST","dispatch_endpoint":null},{"name":"crm.matching.pending_reviews","description":"Get pending contact match reviews that need human attention.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max reviews to return (default 10)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/matching.pending-reviews","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action_required":{},"message":{},"pending_reviews":{},"showing":{},"total_pending":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.matching.run_backfill","description":"Trigger a contact matching backfill for unlinked orders.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max orders to process (default 100)"},"dry_run":{"type":"string","description":"If true, just show what would be matched (default false)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/matching.run-backfill","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"dry_run":{},"message":{},"status":{},"task_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.matching.stats","description":"Get contact matching statistics for the company.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/matching.stats","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"health_status":{},"match_breakdown":{},"opportunities":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.message.send","description":"Send an email or SMS message to a contact.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID (required)"},"channel":{"type":"string","description":"Communication channel (email, sms, call) (required)"},"handle":{"type":"string","description":"Email address or phone number (required)"},"subject":{"type":"string","description":"Message subject (required for email)"},"body":{"type":"string","description":"Message body (required)"},"template_id":{"type":"integer","description":"Optional email template ID to use"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","channel","contact_id","handle"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/message.send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"channel":{},"contact_id":{},"message_id":{},"sent_at":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.photo.send","description":"Send a photo/image to a phone number via MMS.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_phone":{"type":"string","description":"Recipient phone number (E.164 format, e.g. +15551234567)"},"phone":{"type":"string"},"image_url":{"type":"string","description":"Public HTTPS URL of the image to send (jpg/png/gif, under 5MB)"},"message":{"type":"string","description":"Text message to accompany the image"},"contact_id":{"type":"integer","description":"Optional CRM contact ID to associate with"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/photo.send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message_sid":{},"ok":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.preview_contact_merge","description":"Project a contact merge — field survival map + reassignment counts.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"primary_id":{"type":"integer","minimum":1},"secondary_id":{"type":"integer","minimum":1}},"required":["primary_id","secondary_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/preview-contact-merge","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"conflicts":{},"error":{},"error_code":{},"field_survival":{},"missing_ids":{},"primary":{},"reasons":{},"reassignment_total":{},"reassignments":{},"secondary":{},"success":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.product_ideas.create","description":"Create a new product idea for evaluation.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"idea_name":{"type":"string","description":"Name of the product idea (required)"},"idea_description":{"type":"string","description":"Detailed description (required)"},"category":{"type":"string","description":"Main category (pain, technology, clone) (required)"},"rating":{"type":"string","description":"User's initial rating (best, good, okay, bad) (required)"},"pain_sub_category":{"type":"string","description":"Pain subcategory (at_work, private_life)"},"pain_sub_sub_category":{"type":"string","description":"Pain sub-subcategory (my_work, others_work, my_life)"},"technology_sub_category":{"type":"string","description":"Technology subcategory (application, life_of_people_i_know, people_i_dont_know)"},"clone_sub_category":{"type":"string","description":"Clone subcategory (oss, new_pricing, new_niche, new_geography, new_use_case)"},"additional_notes":{"type":"string","description":"Optional notes"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["idea_name"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/product-ideas.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"category":{},"category_path":{},"created_at":{},"id":{},"idea_name":{},"status":{},"user_rating":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.product_ideas.get","description":"Read one product idea from crm_product_ideas by product_idea_id, tenant-scoped. Returns name, description, category, rating, notes, status and the stored AI review with reviewer and timestamps.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_idea_id":{"type":"integer","description":"Product idea ID (required)"}},"required":["product_idea_id"]},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/product-ideas.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"additional_notes":{},"ai_review":{},"category":{},"category_path":{},"created_at":{},"id":{},"idea_description":{},"idea_name":{},"reviewed_at":{},"reviewed_by_agent":{},"status":{},"updated_at":{},"user_rating":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.product_ideas.list","description":"List product ideas with filtering and sorting.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Filter by status (pending_review, reviewed, implemented, archived)"},"category":{"type":"string","description":"Filter by category (pain, technology, clone)"},"rating":{"type":"string","description":"Filter by user rating (best, good, okay, bad)"},"limit":{"type":"integer","description":"Max results (default 50)"},"offset":{"type":"integer","description":"Pagination offset"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/product-ideas.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"limit":{},"offset":{},"product_ideas":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.product_ideas.review","description":"AI-powered strategic review of a product idea by Morgan (Strategy Director).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_idea_id":{"type":"integer","description":"Product idea ID (required)"},"agent_name":{"type":"string","description":"Name of the reviewing agent (default: Morgan)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_idea_id"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/product-ideas.review","http_method":"POST","dispatch_endpoint":null},{"name":"crm.sms.send","description":"Send an SMS text message to a phone number.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_phone":{"type":"string","description":"Recipient phone number (E.164 format, e.g. +15551234567)"},"phone":{"type":"string"},"message":{"type":"string","description":"Text message to send (keep under 160 chars for best delivery)"},"contact_id":{"type":"integer","description":"Optional CRM contact ID to associate with"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":"sms.send","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/sms.send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message_sid":{},"ok":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tags_apply","description":"Apply tags to a contact. tags is a comma-separated string. mode=append (default) adds new tags to existing; mode=replace overwrites the whole tags field; mode=remove strips matching tags.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id."},"tags":{"type":"string","description":"Comma-separated tags (e.g. 'vip,recurring,dental'). Max 512 chars total.","minLength":1,"maxLength":512},"mode":{"type":"string","enum":["append","replace","remove"],"description":"How to apply. Default 'append'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","tags"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tags-apply","http_method":"POST","dispatch_endpoint":null},{"name":"crm.tasks.complete","description":"Mark a task in the tenant's CRM task table (crm_tasks, not Google Tasks) completed and stamp completed_at; requires task_id. Emits crm.task.completed, logs a contact activity if linked, returns the task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_id":{"type":"integer","description":"Task ID (required)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.complete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"completed_at":{},"id":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tasks.create","description":"Create a task in the tenant's CRM task table (crm_tasks, not Google Tasks); requires title, optional description, priority, status, ISO due_date, contact_id, deal_id, assigned_to. Returns the new task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"due_date":{"type":"string","description":"Due date ISO format (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS)"},"title":{"type":"string","description":"Task title (required)"},"description":{"type":"string","description":"Task description"},"priority":{"type":"string","description":"low, medium, or high (default: medium)"},"status":{"type":"string","description":"Task status (default: pending)"},"contact_id":{"type":"integer","description":"Associated contact ID"},"deal_id":{"type":"integer","description":"Associated deal ID"},"assigned_to":{"type":"string","description":"User ID to assign task to"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"created_at":{},"due_date":{},"id":{},"priority":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tasks.delete","description":"Permanently delete a task from the tenant's CRM task table (crm_tasks, not Google Tasks) by integer task_id. Returns task_id and deleted true; errors if the task is not in this tenant.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_id":{"type":"integer","description":"Task ID (required)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deleted":{},"task_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tasks.list","description":"List tasks from the tenant's CRM task table (crm_tasks), soonest due first; filters status, priority, contact_id, deal_id, assigned_to, overdue, due_soon days, limit/offset. Returns tasks and total.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Filter by status (pending, in_progress, completed, cancelled)"},"priority":{"type":"string","description":"Filter by priority (low, medium, high)"},"contact_id":{"type":"integer","description":"Filter by contact"},"deal_id":{"type":"integer","description":"Filter by deal"},"assigned_to":{"type":"string","description":"Filter by assigned user ID"},"overdue":{"type":"boolean","description":"Show only overdue tasks (true/false)"},"due_soon":{"type":"string","description":"Show tasks due within N days"},"limit":{"type":"integer","description":"Max results (default 50)"},"offset":{"type":"integer","description":"Pagination offset"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.list","http_method":"POST","dispatch_endpoint":null},{"name":"crm.tasks.productivity_summary","description":"Get productivity metrics for task completion.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"string","description":"Number of days to analyze (default 30)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.productivity-summary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_completion_days":{},"completed_count":{},"completion_rate_percent":{},"overdue_count":{},"overdue_tasks":{},"pending_count":{},"period_days":{},"priority_breakdown":{},"total_tasks":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tasks.suggest_next_actions","description":"AI suggestion: Generate intelligent task recommendations.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Suggest tasks for specific contact"},"deal_id":{"type":"integer","description":"Suggest tasks for specific deal"},"limit":{"type":"integer","description":"Max suggestions"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.suggest-next-actions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"suggestions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.tasks.update","description":"Change fields on a task in the tenant's CRM task table (crm_tasks, not Google Tasks) by task_id: title, description, priority, status, assignee, due_date. Returns id, title, status, priority, due_date.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_id":{"type":"integer","description":"Task ID (required)"},"title":{"type":"string","description":"New title"},"description":{"type":"string","description":"New description"},"priority":{"type":"string","description":"New priority"},"status":{"type":"string","description":"New status"},"assigned_to":{"type":"string","description":"New assignee user ID"},"due_date":{"type":"string","description":"New due date"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id"]},"required_scope":"crm:write","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/tasks.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"due_date":{},"id":{},"priority":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm.timeline.get","description":"Get complete timeline for a contact or deal.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID"},"deal_id":{"type":"integer","description":"Deal ID"},"limit":{"type":"integer","description":"Max items per type (default 50)"},"include_types":{"type":"string","description":"Comma-separated types to include (activities, messages, tasks)"}}},"required_scope":"crm:read","transport":"http","coordinate":"37","noun":"crm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/crm/timeline.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"count":{},"deal_id":{},"timeline":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_contact_update","description":"Update safe fields on an existing contact: first_name, last_name, email, tags. Phone changes are NOT supported here — they require a separate higher-confirmation flow.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id to update."},"first_name":{"type":"string","description":"New first name."},"last_name":{"type":"string","description":"New last name."},"email":{"type":"string","description":"New email address."},"tags":{"type":"string","description":"Comma-separated tags. Replaces existing tags string.","maxLength":512},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"contact.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"fields_updated":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_contacts_create","description":"Create a new CRM contact when crm_contacts_search returned zero matches and the user wants to add the person. Returns a confirmation card — the contact is NOT created until the user clicks Confirm. After creation, the caller can call voice_outbound_call or sms_send against the new contact_id (consent flags will still gate dispatch).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name (optional)."},"phone":{"type":"string","description":"E.164 phone like +18005551234 (optional but required for voice/SMS)."},"email":{"type":"string","description":"Email (optional)."},"voice_consent_status":{"type":"string","description":"Set to 'granted' only if the user confirmed verbal consent. Default 'pending'.","enum":["pending","granted"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["first_name"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.contacts.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"email":{},"name":{},"phone":{},"preflight":{},"status":{},"voice_consent_status":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_contacts_search","description":"Search across CRM contacts, lead submissions, upcoming appointments, AND the company's team members (users). Always start here when the user references a person (call X, text X, email X). Multi-word queries are tokenized — 'Adam Campbell' finds a contact with first_name=Adam, last_name=Campbell. Returns four lists:   - contacts: real CRM rows.   - leads: form submissions not yet promoted to a contact.   - upcoming_appointments: next 30 days of meetings tied to a matched contact.   - team_members: users on this company's team (may include     the person currently chatting with you — flagged is_you=true). Resolution rules:   - team_member with is_you=true → the user is referencing     THEMSELVES. Don't dispatch outbound to them; clarify     \"you mean YOU, or another person?\"   - found in contacts → use the contact_id directly.   - found in leads only → tell the user 'looks like they     submitted a form on <date>; want me to add them to the     CRM?' and call crm_contacts_create with the lead's     email/phone on confirm.   - found in upcoming_appointments → use that to brief the     dispatched agent (\"appointment at 3pm tomorrow\").   - found NOWHERE → ask the user for phone/email and call     crm_contacts_create to add them. Don't guess data.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Name, phone, email, or numeric contact ID. Min 2 chars (or all digits for ID lookup)."}},"required":["query"]},"required_scope":"crm:read","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.contacts.search","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contacts":{},"leads":{},"message":{},"team_members":{},"total":{},"upcoming_appointments":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_context_get","description":"Get recent CRM activity for a contact so the dispatched agent has full context before reaching out: last few calls/SMS, open deals, open tasks. Read-only. Use before voice_outbound_call to brief the call.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact ID owned by this company."}},"required":["contact_id"]},"required_scope":"crm:read","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.context_get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact":{},"open_deals":{},"recent_calls":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_deal_advance","description":"Move an existing deal to a new stage. Use this when the user says 'mark the Acme deal as qualified' or 'move that one to proposal'. Does not change amount or other fields.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"crm_deals.id to advance."},"new_stage":{"type":"string","description":"New stage. Must be a valid pipeline stage."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","new_stage"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.deals.update_stage","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"deal_id":{},"ok":{},"stage":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_deal_create","description":"Create a sales opportunity (deal) in the CRM pipeline. Tie it to a contact_id if there's a known buyer. Default stage 'new'. Amount is optional but recommended — without it pipeline value reports won't include this deal.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Deal title (e.g. 'Q3 implementation'). 3–256 chars.","minLength":3,"maxLength":256},"stage":{"type":"string","description":"Stage. Default 'new'. Common: new, qualified, discovery, proposal, negotiation."},"amount_cents":{"type":"integer","description":"Deal value in cents. Optional.","minimum":0},"contact_id":{"type":"integer","description":"Optional crm_contacts.id of the buyer."},"notes":{"type":"string","description":"Optional free-text notes."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"deal.create","status":"active","inverse":null,"refuses_when":[{"code":"invalid_stage","when":"The stage is not one of new, qualified, discovery, proposal, negotiation, won, lost, closed_won, closed_lost, cancelled.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount_usd":{},"company_id":{},"deal_id":{},"ok":{},"stage":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_deals_follow_up","description":"Create a follow-up task for EVERY deal in a stage — for example all deals still in 'New' — with ONE confirmation for the whole batch. Use when the owner says yes to following up on a group of deals, such as the next step in their report. Deals that already have an open follow-up task are skipped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"stage":{"type":"string","description":"Deal stage to follow up, e.g. 'New' (case-insensitive)."},"created_within_days":{"type":"integer","description":"Only deals created in the last N days. Default 30."},"due_in_days":{"type":"integer","description":"Tasks are due this many days from now. Default 1."},"priority":{"type":"string","enum":["low","medium","high"],"description":"Priority. Default 'medium'."},"max_deals":{"type":"integer","description":"Safety cap on how many deals to follow up. Default 50, max 200."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["stage"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.deals_follow_up","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"created":{},"deals_in_stage":{},"due_in_days":{},"ok":{},"preview":{},"skipped_already_had_follow_up":{},"stage":{},"task_ids":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_lead_promote","description":"Promote a lead_submission to a real CRM contact. Use when crm_contacts_search returned a hit in the `leads` list (a lead form was submitted but never turned into a contact). Copies the lead's name/email/phone onto a new Contact row and back-links lead.contact_id so it won't show as unpromoted again. Returns a confirmation card — the promote does NOT happen until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","description":"ID of the LeadSubmission to promote."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["lead_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.leads_promote","status":"active","inverse":null,"refuses_when":[{"code":"already_promoted","when":"The lead already has a contact; returns that contact_id as success, nothing new is created.","override":null,"code_in_response":true},{"code":"lead_empty","when":"The lead has no name, email or phone to copy.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"email":{},"lead_id":{},"name":{},"phone":{},"preflight":{},"status":{},"would_promote":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_note_add","description":"Attach a note to a CRM contact — call summary, meeting notes, follow-up reminder, or general context. The note is timestamped and attributed to the current user. Use this when the user says 'note that Jane wants to wait until Q3' or 'log that I left them a voicemail'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id to attach this note to."},"content":{"type":"string","description":"The note body. 1–10,000 chars.","minLength":1,"maxLength":10000},"note_type":{"type":"string","enum":["call","email","follow_up","general","meeting","task"],"description":"What kind of note. Default 'general'. Use 'call' for phone call summaries, 'meeting' for in-person notes, 'email' for correspondence summaries, 'follow_up' for reminders, 'task' for action items."},"title":{"type":"string","description":"Optional short title for the note. Max 256 chars.","maxLength":256},"is_pinned":{"type":"boolean","description":"Pin this note to the top of the contact's note list. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","content"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"contact.add_note","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"is_pinned":{},"note_id":{},"note_type":{},"ok":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_tag_apply","description":"Apply tags to a contact. tags is a comma-separated string. mode=append (default) adds new tags to existing; mode=replace overwrites the whole tags field; mode=remove strips matching tags.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id."},"tags":{"type":"string","description":"Comma-separated tags (e.g. 'vip,recurring,dental'). Max 512 chars total.","minLength":1,"maxLength":512},"mode":{"type":"string","enum":["append","replace","remove"],"description":"How to apply. Default 'append'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","tags"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.tags_apply","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"mode":{},"ok":{},"tags":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_task_create","description":"Create a follow-up task for the team. Optionally tie it to a contact_id (so it shows on the contact's timeline) or a deal_id. Use this when the user says 'remind me to ...' or 'follow up with ... next week'. Default priority medium, status pending.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Short title for the task. 3–256 chars.","minLength":3,"maxLength":256},"description":{"type":"string","description":"Optional longer description / notes."},"contact_id":{"type":"integer","description":"Optional crm_contacts.id to link the task to."},"deal_id":{"type":"integer","description":"Optional crm_deals.id to link the task to."},"priority":{"type":"string","enum":["low","medium","high"],"description":"Priority. Default 'medium'."},"due_date":{"type":"string","description":"ISO date or datetime (YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS). Optional."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.tasks.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"priority":{},"status":{},"task_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"crm_task_update","description":"Update an existing CRM task — most commonly its status (mark it 'completed', 'in_progress', or 'cancelled'), and optionally its priority or due date. Use after a task is done or its plan changes.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_id":{"type":"integer","description":"crm_tasks.id to update."},"status":{"type":"string","enum":["pending","in_progress","completed","cancelled"],"description":"New status."},"priority":{"type":"string","enum":["low","medium","high"],"description":"Optional new priority."},"due_date":{"type":"string","description":"Optional new ISO date/datetime."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"37","noun":"crm","location":"svc.api","same_as":"crm.tasks.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"error":{},"found":{},"ok":{},"status":{},"task_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"customer.full_context","description":"Aggregate customer + orders + interactions + lifecycle + tickets in one call.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"customer_id":{"type":"integer","minimum":1},"include_payment_methods":{"type":"boolean","default":false},"include_orders":{"type":"boolean","default":true},"include_interactions":{"type":"boolean","default":true},"include_tickets":{"type":"boolean","default":true},"include_lifecycle":{"type":"boolean","default":true},"orders_limit":{"type":"integer","default":25,"minimum":1},"interactions_limit":{"type":"integer","default":25,"minimum":1}},"required":["customer_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"customer","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/customer/full-context","http_method":"POST","dispatch_endpoint":null},{"name":"customer.suggest_upsell","description":"Suggest products the customer might buy next.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"customer_id":{"type":"integer","minimum":1},"category":{"type":"string","nullable":true},"top_k":{"type":"integer","minimum":1,"maximum":100,"default":10}},"required":["customer_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"customer","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/customer/suggest-upsell","http_method":"POST","dispatch_endpoint":null},{"name":"customer_credit.apply","description":"Apply a credit memo to a contact's ledger. Reduces what they owe on next invoice. IRREVERSIBLE — owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer"},"amount_cents":{"type":"integer","minimum":1},"reason":{"type":"string","maxLength":500},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","amount_cents","reason"]},"required_scope":"ops:write","transport":"http","coordinate":"512","noun":"customer_credit","acts_on":{"noun":"customer_credit","address":"512","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/customer_credit/apply","http_method":"POST","dispatch_endpoint":null},{"name":"data.export_contact","description":"Export everything the tenant holds about a single contact for GDPR Article 20 / data portability. Returns a JSON document with the contact + deals + tasks + notes + voice calls + appointments + orders + invoices. Read-style verb (no destructive action), but it's still gated through the confirmation card because it produces a downloadable PII bundle and you want a human ack on that.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"ID of the contact to export."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"gdpr:write","transport":"http","coordinate":"09","noun":"data","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/data/export-contact","http_method":"POST","dispatch_endpoint":null},{"name":"data_export_contact","description":"Export everything the tenant holds about a single contact for GDPR Article 20 / data portability. Returns a JSON document with the contact + deals + tasks + notes + voice calls + appointments + orders + invoices. Read-style verb (no destructive action), but it's still gated through the confirmation card because it produces a downloadable PII bundle and you want a human ack on that.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"ID of the contact to export."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"gdpr:write","transport":"dispatch","coordinate":"09","noun":"data","location":"svc.api","same_as":"data.export_contact","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"bundle":{},"contact_id":{},"preflight":{},"status":{},"tables":{},"tables_to_export":{},"total_rows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.advance","description":"Move a deal forward one stage in the pipeline (new → qualified → proposal_sent → negotiation → won). Refuses to skip stages; use deals_update if you need to jump. Returns a confirmation card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the deal."},"to_stage":{"type":"string","enum":["new","qualified","proposal_sent","negotiation","won"],"description":"Next stage (must be exactly one step forward)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","to_stage"]},"required_scope":"crm:write","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"stage_skip_not_allowed","when":"to_stage is not exactly the next step of new → qualified → proposal_sent → negotiation → won.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/advance","http_method":"POST","dispatch_endpoint":null},{"name":"deal.close","description":"Close a deal as Won or Lost; the reason is appended to the deal's notes and crm.deal.won / crm.deal.lost is emitted.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"won":{"type":"boolean","default":true},"close_reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/close","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"close_reason":{},"deal_id":{},"outcome":{},"stage":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.create","description":"Create a CRM deal in the tenant's pipeline; logs the activity and emits crm.deal.created. `amount_cents` is cents, matching the column. `stage` accepts any known spelling and is stored in canonical Title Case.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"contact_id":{"type":"integer","nullable":true},"amount_cents":{"type":"integer","nullable":true},"stage":{"type":"string","default":"New"},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount_cents":{},"deal_id":{},"stage":{},"status":{},"summary":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.explain_stage_change","description":"Explain why a CRM deal (crm_deals) by deal_id reached its stage, from its audit_logs entries and recent reassignment. Optional from_stage/to_stage narrow the search; returns factors and a narrative.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"from_stage":{"type":"string","nullable":true},"to_stage":{"type":"string","nullable":true}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/explain-stage-change","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deal":{},"error":{},"error_code":{},"factors":{},"narrative":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.full_narrative","description":"Deal + tasks + activities + crm-messages + proposals.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"limit_per_source":{"type":"integer","minimum":1,"maximum":200,"default":50}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/full-narrative","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"activities":{},"counts":{},"deal":{},"error":{},"error_code":{},"messages":{},"proposals":{},"success":{},"tasks":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.pipeline_report","description":"Return the current sales pipeline grouped by stage. Counts and total amount per stage for OPEN deals only (excludes won/lost/closed/cancelled). Read-only. Use this when the user asks 'where are my deals?' or 'show me the pipeline'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"crm:read","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/pipeline-report","http_method":"POST","dispatch_endpoint":null},{"name":"deal.search","description":"Search this company's CRM deals. Filter by stage (new, qualified, proposal_sent, negotiation, won, lost) and/or contact_id. Returns up to 10 deals sorted by most recently updated. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Optional fuzzy match on deal title."},"stage":{"type":"string","description":"Filter by stage.","enum":["new","qualified","proposal_sent","negotiation","won","lost"]},"contact_id":{"type":"integer","description":"Filter to deals attached to this contact."}}},"required_scope":"crm:read","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/search","http_method":"POST","dispatch_endpoint":null},{"name":"deal.suggest_next_action","description":"Ranked next-action suggestions for a deal.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:read","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/suggest-next-action","http_method":"POST","dispatch_endpoint":null},{"name":"deal.update","description":"Update a CRM deal. `amount_cents` is cents, matching the column.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"amount_cents":{"type":"integer","nullable":true},"stage":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deal_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deal.won","description":"Mark a deal as won (closed). Optionally set the final amount_cents. Returns a confirmation card — this is a permanent revenue-attribution event.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the deal."},"amount_cents":{"type":"integer","description":"Final closed-won value in cents."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"33","noun":"deal","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/deal/won","http_method":"POST","dispatch_endpoint":null},{"name":"deal_get","description":"Get a single CRM deal by id — stage, amount, contact, notes, and timestamps. Read-only. Returns found=false if the deal does not belong to this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"CRM deal id owned by this company."}},"required":["deal_id"]},"required_scope":"crm:read","transport":"dispatch","coordinate":"33","noun":"deal","location":"svc.api","same_as":"crm.deals.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount_cents":{},"assigned_to_user_id":{},"contact_id":{},"created_at":{},"deal_id":{},"follow_up_date":{},"found":{},"note":{},"notes":{},"ok":{},"stage":{},"title":{},"updated_at":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_advance","description":"Move a deal forward one stage in the pipeline (new → qualified → proposal_sent → negotiation → won). Refuses to skip stages; use deals_update if you need to jump. Returns a confirmation card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the deal."},"to_stage":{"type":"string","enum":["new","qualified","proposal_sent","negotiation","won"],"description":"Next stage (must be exactly one step forward)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","to_stage"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"deal.advance","status":"active","inverse":null,"refuses_when":[{"code":"stage_skip_not_allowed","when":"to_stage is not exactly the next step of new → qualified → proposal_sent → negotiation → won.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_stage":{},"deal":{},"preflight":{},"status":{},"to_stage":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_create","description":"Create a new sales deal in the CRM. Returns a confirmation card; the deal is NOT created until the user clicks Confirm. Default stage is 'new'. Always link to a contact_id (use crm_contacts_search or crm_contacts_create first to resolve).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Short deal title (e.g. \"Acme HVAC retrofit\")."},"contact_id":{"type":"integer","description":"Owning CRM contact ID in this company."},"amount_cents":{"type":"integer","description":"Deal value in cents (optional)."},"stage":{"type":"string","enum":["new","qualified","proposal_sent","negotiation","won","lost"],"description":"Initial stage. Default 'new'."},"notes":{"type":"string","description":"Optional context for the deal."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","contact_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"deal.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"contact_name":{},"deal":{},"message":{},"preflight":{},"stage":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_list","description":"List this company's CRM deals (the pipeline), most recently updated first. Optionally filter by stage. Read-only. Returns an empty list if there are none — do not invent deals.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"stage":{"type":"string","description":"Optional pipeline stage filter."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max deals to return. Default 25."}}},"required_scope":"crm:read","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"crm.deals.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"deals":{},"found":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_search","description":"Search this company's CRM deals. Filter by stage (new, qualified, proposal_sent, negotiation, won, lost) and/or contact_id. Returns up to 10 deals sorted by most recently updated. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Optional fuzzy match on deal title."},"stage":{"type":"string","description":"Filter by stage.","enum":["new","qualified","proposal_sent","negotiation","won","lost"]},"contact_id":{"type":"integer","description":"Filter to deals attached to this contact."}}},"required_scope":"crm:read","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"deal.search","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"deals":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_update","description":"Update an existing deal's stage, amount, follow-up date, or notes. Returns a confirmation card; the deal is NOT updated until the user clicks Confirm. For stage transitions to 'won'/'lost', use the simpler `deals_advance` / `deals_won` verbs instead.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the deal to update."},"stage":{"type":"string","enum":["new","qualified","proposal_sent","negotiation","won","lost"],"description":"New stage."},"amount_cents":{"type":"integer","description":"Updated deal value in cents."},"follow_up_date":{"type":"string","description":"ISO-8601 follow-up datetime (YYYY-MM-DDTHH:MM:SS)."},"notes":{"type":"string","description":"Replace the deal's notes."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"deal.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"changes":{},"current":{},"deal":{},"preflight":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deals_won","description":"Mark a deal as won (closed). Optionally set the final amount_cents. Returns a confirmation card — this is a permanent revenue-attribution event.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the deal."},"amount_cents":{"type":"integer","description":"Final closed-won value in cents."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"39","noun":"deals","location":"svc.api","same_as":"deal.won","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current":{},"deal":{},"preflight":{},"status":{},"would_close_with_amount":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"deployment_trigger","description":"ADA does NOT deploy to production. Production deploys are human-driven via ./deploy.sh. This verb exists so the LLM gets a deliberate 'not allowed' response instead of hallucinating a path. To deploy, the human operator runs ./deploy.sh on their workstation.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"deployment","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"design.capabilities","description":"Everything an agent can actually change about how this tenant's site looks, in one call: the 8 themes, the 3 motion profiles and 9 per-block reveal presets, and every block type with the exact prop names the renderer reads. Also names what does NOT exist (per-breakpoint/mobile overrides) and where the rest lives (asset upload, custom CSS/fonts, scripts), so an agent stops looking for knobs that would return 200 and change nothing. A design coming from another tool: design.intake. Call this before designing.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/capabilities","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"blocks":{},"company_id":{},"error":{},"motion":{},"not_available":{},"success":{},"theme":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"design.connect_figma","description":"Connect this business to Figma ONCE: returns a Figma sign-in link for the account owner to open and click Allow. After that, any Figma design link can be pulled in server-side — nobody exports or uploads files. The link expires in 10 minutes.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"return_to":{"type":"string","nullable":true,"maxLength":300}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/connect-figma","http_method":"POST","dispatch_endpoint":null},{"name":"design.create_idea","description":"Design — record a design idea. NOT IMPLEMENTED; always raises. The design_ideas table does not exist (no model, no migration). Use design.generate, or page.create / site.create.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"description":{"type":"string"},"style":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["description"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/create-idea","http_method":"POST","dispatch_endpoint":null},{"name":"design.create_site_draft","description":"Design — create a draft site: a named site that is not live (site.create with is_live=false). Templates: site.templates.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"template":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/create-site-draft","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"draft":{},"name":{},"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"design.disconnect_figma","description":"Disconnect Figma for this business and delete the stored token.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/disconnect-figma","http_method":"POST","dispatch_endpoint":null},{"name":"design.edit","description":"AI-edit an existing design screen from a text prompt (Stitch). Returns updated layout_json sections. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string","description":"Screen id from design_generate/design_screens."},"prompt":{"type":"string","minLength":1,"description":"The change to make."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","screen_id","prompt"]},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/edit","http_method":"POST","dispatch_endpoint":null},{"name":"design.figma_status","description":"Whether this business has connected Figma, and as which Figma account.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/figma-status","http_method":"POST","dispatch_endpoint":null},{"name":"design.generate","description":"AI-generate a page design from a text prompt (Stitch). Returns layout_json sections you then save with edit_page_content. Uses AI credits. Requires the design engine to be enabled.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id (group related screens)."},"prompt":{"type":"string","minLength":1,"description":"What to design."},"device_type":{"type":"string","enum":["DESKTOP","MOBILE"],"description":"Default DESKTOP."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","prompt"]},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/generate","http_method":"POST","dispatch_endpoint":null},{"name":"design.generate_page","description":"Design — turn a design idea into a page. NOT IMPLEMENTED; always raises. The design_ideas table does not exist. Use design.generate or page.create.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"idea_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["idea_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/generate-page","http_method":"POST","dispatch_endpoint":null},{"name":"design.import","description":"Convert a piece of existing HTML into editable page sections (layout_json) you can save with edit_page_content. Pure conversion — no AI cost, always available. ⛔ NOT the way to clone a whole website: this keeps the copy and drops the CSS, fonts and motion, and leaves no import to roll back. To copy / migrate / rebuild a site the business already has, use nest_import_url (an address) or nest_import (a file or folder) — the one clone door, with preview → execute → promote → publish and a fidelity score.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"html":{"type":"string","minLength":1,"description":"The HTML to import."}},"required":["html"]},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/import","http_method":"POST","dispatch_endpoint":null},{"name":"design.import_figma","description":"PORT A FIGMA DESIGN into a real page. Use with Figma's own MCP server: call its get_design_context on the frame asking for \"plain HTML + CSS\", and download_assets for its images; pass the html here (plus assets=[{name, content_base64}] for any image whose URL is localhost — Figma's desktop server). Returns a Nest PREVIEW with an import_id and fidelity score; images are copied into this business's own store. Nothing is created until nest.execute (connector: clone_execute).","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"html":{"type":"string","minLength":1,"description":"The frame's code from Figma's MCP — plain HTML + CSS."},"assets":{"type":"array","nullable":true,"items":{"type":"object"},"description":"[{name, content_base64}] for images Figma served from localhost."},"figma_url":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"options":{"type":"object","nullable":true}},"required":["html"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/import-figma","http_method":"POST","dispatch_endpoint":null},{"name":"design.import_screen","description":"Make an existing Stitch design screen a REAL PAGE. Fetches the screen and runs it through the clone door (the same as clone_website_from_code): returns a PREVIEW with an import_id and a fidelity score; its images are copied into this business's own store (Stitch's image links expire). Nothing is created until clone_execute. Use it after design_generate / design_edit / design_variants — their `next` names it.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id."},"screen_id":{"type":"string","description":"Screen id from design_screens or a generate result."},"options":{"type":"object","description":"Optional import options (as clone_website_from_code)."}},"required":["project_id","screen_id"]},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/import-screen","http_method":"POST","dispatch_endpoint":null},{"name":"design.intake","description":"CALL THIS FIRST when someone brings a design from ANY tool — Figma, Figma Make, Figma Sites, Stitch, Framer, Webflow, Canva, Lovable, v0, Bolt, Wix, Squarespace, a GitHub repo, Sketch, XD, Penpot. Pass their link (or the tool's name) and get the exact way it comes in: which call, what it needs, and what you will get. Editor links are never fetched (they would clone a login page); published links come back with the clone call already filled in. No argument returns the whole map. Reads and fetches nothing, so it is safe to call every time.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"source":{"type":"string","nullable":true,"maxLength":2000,"description":"The design's link, or the tool's name (e.g. 'Figma Make')."}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/intake","http_method":"POST","dispatch_endpoint":null},{"name":"design.lock","description":"Lock this site's design so edits are refused. mode='locked' refuses everything; mode='copy-only' still allows copy edits, media swaps and publishing, which is what an agency usually wants for a client it built for. Takes effect on every surface at once — dashboard, connector, WebMCP, CLI and our own agents — because the check lives in the CMS writer, not in a UI.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1,"nullable":true},"mode":{"type":"string","enum":["locked","copy-only"],"default":"locked"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":"design.unlock","refuses_when":[{"code":"site_ambiguous","when":"No site_id and the company has zero or several sites.","override":"site_id","code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/lock","http_method":"POST","dispatch_endpoint":null},{"name":"design.lock_status","description":"Is this site's design locked, and what may you still change? Returns the mode (locked / open / copy-only / custom), an explicit `you_may_change` and `you_may_not_change` list, any per-field allowlist an agency set, AND the separate company-level agency lock — a site can be open in one and refused by the other. ⛔ READ THIS BEFORE EDITING A SITE YOU DID NOT BUILD. A refused write is this lock working, not a platform fault. No guardrails row means OPEN: a site nobody locked belongs to its owner.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1,"nullable":true,"description":"Required when the company has more than one site."}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"site_ambiguous","when":"No site_id and the company has zero or several sites.","override":"site_id","code_in_response":false}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/lock-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agency_lock":{},"configured":{},"editable_fields":{},"error":{},"mode":{},"note":{},"site_id":{},"status":{},"you_may_change":{},"you_may_not_change":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"design.pull_figma","description":"PULL A FIGMA DESIGN BY ITS LINK into a real page — no Figma MCP needed. Pass a figma.com/design link (right-click a frame → Copy link to selection). Solid# reads the frame from Figma with this business's Figma connection and rebuilds it: text stays real text, images are kept in this business's store, it scales to every width. Returns a Nest PREVIEW (then nest.execute). If Figma isn't connected yet it returns status needs_connection with connect_url — a one-click link for the user; then pull again.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"url":{"type":"string","minLength":1,"description":"A figma.com/design (or file/proto) link."},"options":{"type":"object","nullable":true}},"required":["url"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/pull-figma","http_method":"POST","dispatch_endpoint":null},{"name":"design.screens","description":"List the screens in a Stitch design project. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id."}},"required":["project_id"]},"required_scope":null,"transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/screens","http_method":"POST","dispatch_endpoint":null},{"name":"design.unlock","description":"Open this site's design back up so edits are allowed again. Sets the mode to 'open' rather than deleting the guardrails row — deleting it would lose any per-field allowlist an agency configured and would read identically to 'never configured'.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1,"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":"design.lock","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/unlock","http_method":"POST","dispatch_endpoint":null},{"name":"design.variants","description":"Generate several design options for a screen (Stitch) — the 'give me 3 options' move. Returns a list of layout_json variants. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string"},"prompt":{"type":"string","description":"Optional direction for the variants."},"variant_count":{"type":"integer","minimum":1,"maximum":5,"description":"Default 3."},"creative_range":{"type":"string","enum":["REFINE","EXPLORE","REIMAGINE"],"description":"How far to roam. Default EXPLORE."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","screen_id"]},"required_scope":"pages:write","transport":"http","coordinate":"75","noun":"design","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/design/variants","http_method":"POST","dispatch_endpoint":null},{"name":"design_edit","description":"AI-edit an existing design screen from a text prompt (Stitch). Returns updated layout_json sections. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string","description":"Screen id from design_generate/design_screens."},"prompt":{"type":"string","minLength":1,"description":"The change to make."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","screen_id","prompt"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.edit","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"design_generate","description":"AI-generate a page design from a text prompt (Stitch). Returns layout_json sections you then save with edit_page_content. Uses AI credits. Requires the design engine to be enabled.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id (group related screens)."},"prompt":{"type":"string","minLength":1,"description":"What to design."},"device_type":{"type":"string","enum":["DESKTOP","MOBILE"],"description":"Default DESKTOP."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","prompt"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.generate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"design_import","description":"Convert a piece of existing HTML into editable page sections (layout_json) you can save with edit_page_content. Pure conversion — no AI cost, always available. ⛔ NOT the way to clone a whole website: this keeps the copy and drops the CSS, fonts and motion, and leaves no import to roll back. To copy / migrate / rebuild a site the business already has, use nest_import_url (an address) or nest_import (a file or folder) — the one clone door, with preview → execute → promote → publish and a fidelity score.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"html":{"type":"string","minLength":1,"description":"The HTML to import."}},"required":["html"]},"required_scope":"pages:read","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.import","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"design_import_screen","description":"Make an existing Stitch design screen a REAL PAGE. Fetches the screen and runs it through the clone door (the same as clone_website_from_code): returns a PREVIEW with an import_id and a fidelity score; its images are copied into this business's own store (Stitch's image links expire). Nothing is created until clone_execute. Use it after design_generate / design_edit / design_variants — their `next` names it.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id."},"screen_id":{"type":"string","description":"Screen id from design_screens or a generate result."},"options":{"type":"object","description":"Optional import options (as clone_website_from_code)."}},"required":["project_id","screen_id"]},"required_scope":"pages:read","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.import_screen","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"design_screens","description":"List the screens in a Stitch design project. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","description":"Design project id."}},"required":["project_id"]},"required_scope":"pages:read","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.screens","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"project_id":{},"screens":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"design_variants","description":"Generate several design options for a screen (Stitch) — the 'give me 3 options' move. Returns a list of layout_json variants. Uses AI credits.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string"},"prompt":{"type":"string","description":"Optional direction for the variants."},"variant_count":{"type":"integer","minimum":1,"maximum":5,"description":"Default 3."},"creative_range":{"type":"string","enum":["REFINE","EXPLORE","REIMAGINE"],"description":"How far to roam. Default EXPLORE."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","screen_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"75","noun":"design","location":"svc.api","same_as":"design.variants","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"ok":{},"variants":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devon.docs.search","description":"Search Solid# documentation (internal access).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search query"},"include_internal":{"type":"boolean","description":"If True, search PUBLIC + INTERNAL docs."},"category":{"type":"string","description":"Optional category filter"},"limit":{"type":"integer","description":"Max results (default 20)"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"18","noun":"devon","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devon/docs.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"level":{},"message":{},"query":{},"results":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devon.validators.health_check","description":"Code quality health check across all validators: the latest stored run (status, alert level, summary, recommendations, as_of). Refreshed every 6 hours by a scheduled run; never runs the validators inside the call.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"quick":{"type":"boolean","description":"If True, run quick checks only (imports). Default True for speed."},"include_dependency_scan":{"type":"boolean","description":"If True, include CVE vulnerability scan (slow)."}}},"required_scope":null,"transport":"http","coordinate":"18","noun":"devon","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devon/validators.health-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"alert_level":{},"duration_ms":{},"message":{},"recommendations":{},"status":{},"summary":{},"timestamp":{},"validators":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devon.validators.run","description":"Run one platform code validator (pre-deploy, tenant-isolation, migration-sync, dependency-scan) against the backend codebase, with optional CLI args. Returns status, error and warning counts, details, fixes.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"validator_id":{"type":"string","description":"One of:"},"args":{"type":"array","description":"Optional CLI arguments (e.g., ['--imports'] for pre-deploy)"}},"required":["validator_id"]},"required_scope":null,"transport":"http","coordinate":"18","noun":"devon","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devon/validators.run","http_method":"POST","dispatch_endpoint":null},{"name":"devops.check_cdn_status","description":"HTTP GET a given cdn_url and time it; needs scope ops:devops:read. Returns up or down, status code, response time in ms and the X-Cache header. Probes a URL, not tenant data.","shape":"receipt","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cdn_url":{"type":"string"}},"required":["cdn_url"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"devops","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devops/check-cdn-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devops.check_ssl_cert","description":"Check SSL certificate status and expiration for a domain.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"devops","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devops/check-ssl-cert","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devops.check_url_status","description":"Check if a URL is accessible and responding.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"url":{"type":"string"}},"required":["url"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"devops","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devops/check-url-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devops.monitor_disk_space","description":"Monitor disk space usage for a given path.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"path":{"type":"string"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"devops","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devops/monitor-disk-space","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"devops.restart_service","description":"Restart a system service. ⛔ NOT IMPLEMENTED — it restarts nothing, and now says so. It used to answer ok:true with status 'pending' for a restart that never happened, so an agent told to 'consider devops__restart_service()' when the error rate climbed would read success, stop escalating, and report an unhandled incident as handled. Restart through the deploy tooling instead.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"service_name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["service_name"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"devops","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/devops/restart-service","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"dispute.respond","description":"Submit evidence for a chargeback / dispute. Uploads documents + statement to the processor. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"dispute_id":{"type":"string"},"evidence":{"type":"object","description":"Provider-specific evidence dict (statement, receipt urls, shipping tracking, etc.)"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["dispute_id","evidence"]},"required_scope":"payments:write","transport":"http","coordinate":"542","noun":"dispute","acts_on":{"noun":"dispute","address":"542","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/dispute/respond","http_method":"POST","dispatch_endpoint":null},{"name":"dispute_respond","description":"Submit evidence for a chargeback / dispute. Uploads documents + statement to the processor. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"dispute_id":{"type":"string"},"evidence":{"type":"object","description":"Provider-specific evidence dict (statement, receipt urls, shipping tracking, etc.)"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["dispute_id","evidence"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"542","noun":"dispute","acts_on":{"noun":"dispute","address":"542","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":"dispute.respond","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"document.commit","description":"Turn a reviewed Document Intake read (from document_extract) into a real record: an invoice, estimate, quote, bid or proposal for a customer, or a note on a customer for handwritten job notes. Optionally send it right away: send='email' or 'text' delivers a pay link, 'pay_link' just creates one. Does not record payments (use the payment rails) and does not take supplier receipts (those are expenses).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"document_type":{"type":"string","enum":["invoice","proposal","estimate","quote","bid","job_notes"]},"fields":{"type":"object","description":"The reviewed fields: invoice_number, invoice_date, due_date, bill_to {name, email, phone, address}, line_items [{description, quantity, unit_price, amount}], subtotal, tax, total, notes, title."},"contact_id":{"type":"integer","minimum":1,"description":"The customer, when already known."},"send":{"type":"string","enum":["none","email","text","pay_link"],"default":"none"},"email":{"type":"string","description":"Overrides the email read off the paper."},"phone":{"type":"string","description":"Overrides the phone read off the paper."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["intake_id","document_type","fields"]},"required_scope":"files:write","transport":"http","coordinate":"09","noun":"document","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/document/commit","http_method":"POST","dispatch_endpoint":null},{"name":"document.extract","description":"Read one of the company's files (a photo or PDF already stored — e.g. from the camera) with Document Intake, the same OCR as the web scanner: classifies it (invoice, estimate, quote, bid, proposal, receipt, job notes, contract, processor statement) and pulls vendor, bill-to, line items, tax and total, each with a confidence. A contract also returns fields.contract (every commercial term with its page and words) and a processor statement fields.statement (every fee line) — file those with contract.create / statement.create, never document_commit. Spends one OCR read. Returns an intake_id to review and then document_commit. A file already imported returns the earlier read without spending a credit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1,"description":"The stored file to read (capture.classify / Files)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id"]},"required_scope":"files:write","transport":"http","coordinate":"09","noun":"document","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/document/extract","http_method":"POST","dispatch_endpoint":null},{"name":"document_commit","description":"Turn a reviewed Document Intake read (from document_extract) into a real record: an invoice, estimate, quote, bid or proposal for a customer, or a note on a customer for handwritten job notes. Optionally send it right away: send='email' or 'text' delivers a pay link, 'pay_link' just creates one. Does not record payments (use the payment rails) and does not take supplier receipts (those are expenses).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"document_type":{"type":"string","enum":["invoice","proposal","estimate","quote","bid","job_notes"]},"fields":{"type":"object","description":"The reviewed fields: invoice_number, invoice_date, due_date, bill_to {name, email, phone, address}, line_items [{description, quantity, unit_price, amount}], subtotal, tax, total, notes, title."},"contact_id":{"type":"integer","minimum":1,"description":"The customer, when already known."},"send":{"type":"string","enum":["none","email","text","pay_link"],"default":"none"},"email":{"type":"string","description":"Overrides the email read off the paper."},"phone":{"type":"string","description":"Overrides the phone read off the paper."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["intake_id","document_type","fields"]},"required_scope":"files:write","transport":"dispatch","coordinate":"09","noun":"document","location":"svc.api","same_as":"document.commit","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"document_type":{},"intake_id":{},"preview":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"document_extract","description":"Read one of the company's files (a photo or PDF already stored — e.g. from the camera) with Document Intake, the same OCR as the web scanner: classifies it (invoice, estimate, quote, bid, proposal, receipt, job notes, contract, processor statement) and pulls vendor, bill-to, line items, tax and total, each with a confidence. A contract also returns fields.contract (every commercial term with its page and words) and a processor statement fields.statement (every fee line) — file those with contract.create / statement.create, never document_commit. Spends one OCR read. Returns an intake_id to review and then document_commit. A file already imported returns the earlier read without spending a credit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer","minimum":1,"description":"The stored file to read (capture.classify / Files)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id"]},"required_scope":"files:write","transport":"dispatch","coordinate":"09","noun":"document","location":"svc.api","same_as":"document.extract","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"credits_remaining":{},"document_id":{},"preview":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain.add","description":"Attach a custom domain to a site (starts DNS verification). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to attach the domain to."},"domain":{"type":"string","description":"The custom domain, e.g. 'example.com'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id","domain"]},"required_scope":"domains:write","transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/add","http_method":"POST","dispatch_endpoint":null},{"name":"domain.create","description":"Attaches a custom domain to one of the tenant's sites (custom_domains row with a verification token). Requires site_id and domain; returns domain_id, the DNS records to set, and the certificate enrollment budget.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1},"domain":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id","domain"],"additionalProperties":true},"required_scope":"domains:write","transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain.delete","description":"Detaches a website custom domain (custom_domains) from a site. Requires site_id; pass domain when the site has several. Returns the removed hostname, or ambiguous/no_domain.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1},"domain":{"type":"string","nullable":true,"description":"Which domain, when the site has more than one."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"],"additionalProperties":true},"required_scope":"domains:write","transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"domain":{},"site_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain.dns_records","description":"The exact DNS records to point a domain at Solid#, BEFORE connecting it. Answers \"what IP / what CNAME do I use?\" — apex domains get an A record, subdomains get a CNAME. Nothing is created or changed.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string","minLength":3,"description":"The domain to connect, e.g. example.com or shop.example.com."}},"required":["domain"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/dns-records","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain.enrollment_budget","description":"Whether a domain can actually go LIVE this week, and which upcoming weeks cannot take a new one. Let's Encrypt caps new certificates per registered domain per rolling week; every hostname costs one certificate PER EDGE REPLICA while the stores are unshared, so a domain plus its www can cost four. Nothing counted this before, so enrollment hit the limit blind and the owner found out as a TLS error. `allowed: false` means QUEUE and tell them when — their domain is not wrong, the week is full. Read-only.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string","nullable":true,"description":"Check this hostname specifically. Omit for the forecast alone."},"weeks":{"type":"integer","minimum":1,"maximum":26,"default":6}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/enrollment-budget","http_method":"POST","dispatch_endpoint":null},{"name":"domain.list","description":"Lists every address the tenant is reachable on, from custom_domains and subdomain_mappings scoped by company. Returns hostname, url, kind, site_id, verified, canonical and SSL status per row.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"domains":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain.propagation","description":"Check that the whole internet resolves one of this account's domains to Solid#, not just the resolver we use: asks Google, Cloudflare and Quad9 from here and DNS probes in other US regions and Europe. Answers inconsistent with the wrong addresses and where they were seen when a DNS provider is still serving an old copy of the record to part of the internet — the site then works for some visitors and times out for others. Nothing is changed.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string","minLength":3,"description":"A domain attached to this account, e.g. example.com."}},"required":["domain"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/propagation","http_method":"POST","dispatch_endpoint":null},{"name":"domain.remove","description":"Detach the custom domain from a site (the site keeps its default subdomain). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to detach the domain from."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"]},"required_scope":"domains:write","transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/remove","http_method":"POST","dispatch_endpoint":null},{"name":"domain.verify","description":"Check DNS for a site's custom domain. Marks it verified only if the records actually resolve — it can and does fail.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1},"domain":{"type":"string","nullable":true,"description":"Which domain, when the site has more than one."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"],"additionalProperties":true},"required_scope":"domains:write","transport":"http","coordinate":"76","noun":"domain","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"ambiguous","when":"No domain given and the site serves more than one custom domain; the response lists them.","override":"domain","code_in_response":true},{"code":"not_verified","when":"The routing record or TXT token does not check out yet; the response lists the records to fix.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/domain/verify","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"blocking":{},"checks":{},"domain":{},"records":{},"site_id":{},"ssl_status":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"domain_add","description":"Attach a custom domain to a site (starts DNS verification). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to attach the domain to."},"domain":{"type":"string","description":"The custom domain, e.g. 'example.com'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id","domain"]},"required_scope":"domains:write","transport":"dispatch","coordinate":"76","noun":"domain","location":"svc.api","same_as":"domain.add","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"domain_list","description":"List the custom domains + subdomains configured for this company's sites.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"pages:read","transport":"dispatch","coordinate":"76","noun":"domain","location":"svc.api","same_as":"domain.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"domain_remove","description":"Detach the custom domain from a site (the site keeps its default subdomain). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to detach the domain from."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"]},"required_scope":"domains:write","transport":"dispatch","coordinate":"76","noun":"domain","location":"svc.api","same_as":"domain.remove","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"domain_verify","description":"Re-check DNS and verify a site's custom domain. Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id whose domain to verify."},"domain":{"type":"string","description":"Which domain, when the site has more than one."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"]},"required_scope":"domains:write","transport":"dispatch","coordinate":"76","noun":"domain","location":"svc.api","same_as":"domain.verify","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"draft_review_response","description":"Draft a brief, warm, professional reply to a customer review on behalf of this company. Returns suggested text for a human to review and post — it does NOT publish anything. Handles low-rating reviews gracefully (apologize, invite offline contact).","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"review_text":{"type":"string","description":"The customer's review text."},"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Star rating 1-5, if known."},"reviewer_name":{"type":"string","description":"Reviewer's name, if known."}},"required":["review_text"]},"required_scope":null,"transport":"dispatch","coordinate":"79","noun":"draft","location":"svc.api","same_as":"review.draft_response","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"draft":{},"ok":{},"rating":{},"reviewer_name":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.enroll","description":"Enrolls a CRM contact (crm_contacts) in an active drip sequence by sequence_id and contact_id, writing drip_enrollments. Returns enrollment id, status and next send time; re-enrolling returns the existing one.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sequence_id":{"type":"integer","description":"Sequence ID"},"contact_id":{"type":"integer","description":"Contact ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","sequence_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/enroll","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"current_step":{},"enrollment_id":{},"error":{},"message":{},"next_send_at":{},"sequence_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.pause","description":"Pauses an active drip enrollment (drip_enrollments) by enrollment_id so no further sequence emails are sent to that contact. Returns status paused, or an error if it is not active.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enrollment_id":{"type":"integer","description":"Enrollment ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enrollment_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/pause","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"enrollment_id":{},"error":{},"message":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.resume","description":"Resumes a paused drip enrollment (drip_enrollments) by enrollment_id, setting it active again so sequence emails continue. Returns status active, or an error if it was not paused.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enrollment_id":{"type":"integer","description":"Enrollment ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enrollment_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/resume","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"enrollment_id":{},"error":{},"message":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.sequence.create","description":"Creates an email drip sequence (drip_sequences) with a name and trigger_type (contact_created, deal_stage_changed, tag_added, manual, webhook) plus stop rules. It has no steps yet. Returns the sequence id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Sequence name"},"trigger_type":{"type":"string","description":"Trigger type (contact_created, deal_stage_changed, tag_added, manual, webhook)"},"trigger_config":{"type":"string","description":"Optional trigger configuration (e.g., {\"stage\": \"qualified\", \"tag\": \"trial_started\"})"},"description":{"type":"string","description":"Optional description"},"stop_on_reply":{"type":"boolean","description":"Stop sequence if contact replies (default: False)"},"stop_on_click":{"type":"boolean","description":"Stop sequence if contact clicks any link (default: False)"},"stop_on_conversion":{"type":"boolean","description":"Stop sequence if deal is won (default: False)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","trigger_type"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/sequence.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"id":{},"is_active":{},"message":{},"name":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.sequence.delete","description":"Delete a drip sequence (only if no active enrollments).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sequence_id":{"type":"integer","description":"Sequence ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["sequence_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"has_active_enrollments","when":"The sequence has active or paused enrollments (same message as not-found).","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/sequence.delete","http_method":"POST","dispatch_endpoint":null},{"name":"drip.sequence.update","description":"Updates fields on this company's drip sequence (drip_sequences) by sequence_id — name, description, is_active, stop_on_* and other columns; id, tenant and audit columns are never written. Returns the sequence id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sequence_id":{"type":"integer","description":"Sequence ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["sequence_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/sequence.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"sequence_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.sequences.list","description":"Lists the tenant's email drip sequences (drip_sequences), optionally only active ones. Returns trigger, stop rules, enrolled/completed/stopped counts and completion rate per sequence.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"is_active":{"type":"string","description":"Optional filter by active status"}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/sequences.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"sequences":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.setup","description":"Create an automated drip email sequence for this company — fires on a trigger (new contact, deal stage change, tag added, manual, or webhook) and can stop on reply/click/conversion. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Sequence name, e.g. 'New lead nurture'."},"trigger_type":{"type":"string","enum":["contact_created","deal_stage_changed","tag_added","manual","webhook"],"description":"What starts the sequence."},"description":{"type":"string","description":"Optional description."},"stop_on_reply":{"type":"boolean","description":"Stop if the contact replies. Default false."},"stop_on_click":{"type":"boolean","description":"Stop if the contact clicks a link. Default false."},"stop_on_conversion":{"type":"boolean","description":"Stop if the deal is won. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","trigger_type"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/setup","http_method":"POST","dispatch_endpoint":null},{"name":"drip.stats","description":"🤖 AI-POWERED: Get performance statistics for a drip sequence.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sequence_id":{"type":"integer","description":"Sequence ID"}},"required":["sequence_id"]},"required_scope":null,"transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/stats","http_method":"POST","dispatch_endpoint":null},{"name":"drip.step.add","description":"Adds an email step to a drip sequence (drip_steps): sequence_id, step_number, name, subject, a delay, and a template_id or html/text body. Returns the new step id and number.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sequence_id":{"type":"integer","description":"Sequence ID"},"step_number":{"type":"integer","description":"Step number (1, 2, 3, etc.)"},"name":{"type":"string","description":"Step name"},"subject":{"type":"string","description":"Email subject"},"delay_days":{"type":"integer","description":"Days to wait before sending (default: 0)"},"delay_hours":{"type":"integer","description":"Hours to wait before sending (default: 0)"},"delay_minutes":{"type":"integer","description":"Minutes to wait before sending (default: 0)"},"template_id":{"type":"string","description":"Optional email template ID"},"html_body":{"type":"string","description":"Optional HTML content"},"text_body":{"type":"string","description":"Optional plain text content"},"from_name":{"type":"string","description":"Optional sender name"},"from_email":{"type":"string","description":"Optional sender email"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","sequence_id","step_number","subject"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/step.add","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"id":{},"message":{},"name":{},"step_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"drip.stop","description":"Permanently stops an active or paused drip enrollment (drip_enrollments) by enrollment_id with a reason (replied, clicked, converted, unsubscribed, manual). Returns status stopped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enrollment_id":{"type":"integer","description":"Enrollment ID"},"reason":{"type":"string","description":"Reason for stopping (replied, clicked, converted, unsubscribed, manual)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enrollment_id","reason"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"drip","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/drip/stop","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"enrollment_id":{},"error":{},"message":{},"status":{},"stop_reason":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ecommerce.apply_promo","description":"Ecommerce — apply a promo code to a cart. NOT IMPLEMENTED; always raises. The cart service behind it recognises only hardcoded test codes and cannot see this company's discounts table, so wiring it would apply a fabricated amount.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cart_id":{"type":"integer","minimum":1},"code":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["cart_id","code"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"47","noun":"ecommerce","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ecommerce/apply-promo","http_method":"POST","dispatch_endpoint":null},{"name":"ecommerce.create_shipping","description":"Ecommerce — record an existing shipment's carrier and tracking number on an order (moves processing to shipped). Does NOT buy a label or call a carrier; tracking_number is required.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"carrier":{"type":"string"},"tracking_number":{"type":"string","description":"Required — this verb records a shipment, it cannot create one."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","tracking_number","carrier"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"47","noun":"ecommerce","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ecommerce/create-shipping","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"carrier":{},"company_id":{},"label_purchased":{},"order_id":{},"order_status":{},"status":{},"tracking_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ecommerce.update_order_status","description":"Ecommerce — set an order's status. Real, company-scoped write; returns {'status': 'not_found'} if the order is not this company's.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"status":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","status"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"47","noun":"ecommerce","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ecommerce/update-order-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"new_status":{},"order_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"edit_page_content","description":"Edit a website page's BODY — the actual sections/blocks (layout_json), not just its title/meta (that's page_edit). Call get_block_schema first so the layout_json matches the block schema. Writes to a DRAFT by default (safe to preview); pass publish=true to push it live. This is how you rebuild what a page SAYS by talking.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id (from list_pages)."},"layout_json":{"type":"object","description":"The page body — sections/blocks matching get_block_schema."},"publish":{"type":"boolean","description":"False (default) writes a draft; true pushes live."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","layout_json"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"79","noun":"edit","location":"svc.api","same_as":"page.edit_content","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"page_id":{},"slug":{},"target":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.get_effective_lane","description":"The email identity truth: what the company SELECTED (system/google/microsoft/custom) vs what a send would ACTUALLY use right now, resolved live. degraded=true means a chosen lane is silently falling back to solidhello.com (revoked token, unverified domain) — surface it loudly.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"602","noun":"email_identity","acts_on":{"noun":"email_identity","address":"602","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/get-effective-lane","http_method":"POST","dispatch_endpoint":null},{"name":"email.send","description":"Send an email through the Switchboard — recipient by address or CRM contact_id; the FROM identity is resolved server-side by the live email lane cascade (Gmail/Microsoft/custom domain/solidhello fallback). Recipient validation + suppression lists enforced below the verb. The receipt reports the effective lane and flags silent degradation. Give subject + body, OR `template` (one of the company's email templates, by id or name) + `variables` for its placeholders — a template with any unfilled placeholder is refused, never sent with {{braces}}; a contact_id fills first_name/last_name/name/email.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":["string","array"],"nullable":true,"items":{"type":"string","format":"email"},"maxItems":5,"description":"One address or a list of up to 5."},"to_email":{"type":"string","nullable":true,"format":"email","description":"legacy alias for `to`"},"contact_id":{"type":"integer","nullable":true},"body_type":{"type":"string","enum":["html","text"],"default":"html"},"sender_name":{"type":"string","nullable":true},"reply_to":{"type":"string","nullable":true,"format":"email"},"subject":{"type":"string","nullable":true,"description":"required unless `template` is given"},"body":{"type":"string","nullable":true,"description":"required unless `template` is given"},"template":{"type":["string","integer"],"nullable":true,"description":"one of the company's email templates (email.template_list), by id or name"},"variables":{"type":"object","nullable":true,"description":"values for the template's placeholders (email.template_get lists them)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"640","noun":"email_message","acts_on":{"noun":"email_message","address":"640","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"too_many_recipients","when":"More than 5 recipients — use a campaign.","override":null,"code_in_response":true},{"code":"contact_has_no_email","when":"Only contact_id given and that contact has no email.","override":"to","code_in_response":true},{"code":"template_inactive","when":"The named template is not active.","override":null,"code_in_response":true},{"code":"template_not_renderable","when":"A required placeholder is missing or wrongly typed; the response lists missing and wrong_type.","override":null,"code_in_response":true},{"code":"send_failed","when":"A recipient is suppressed or invalid, or the company's email limit is reached; the detail says which.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"contact_name":{},"detail":{},"error":{},"from_address":{},"lane":{},"message_id":{},"provider":{},"sent":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.send_invoice","description":"Emails a tenant invoice (invoices table, by invoice_id) to its customer with the PDF attached and a link to the customer's own page when the invoice came from an estimate. Goes to the invoice's customer (crm_contacts) unless contact_id (a crm_contacts id) or email says otherwise. Returns sent with sent_to, invoice_number and pdf_attached; an email that did not go is an error, never sent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"contact_id":{"type":"integer","minimum":1,"nullable":true},"email":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/send-invoice","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"invoice_id":{},"invoice_number":{},"status":{},"summary":{},"to_email":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.template_check","description":"⭐ Would this template render with these values? Costs nothing, sends nothing. Returns would_send plus every problem at once — missing values and wrong types — so you fix them in one pass instead of discovering them one send at a time. ⛔ CALL THIS BEFORE SENDING A TEMPLATED EMAIL. A send with an unresolved placeholder is now refused, and before that it put visible braces in a real customer's inbox.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"integer","minimum":1},"variables":{"type":"object","nullable":true,"description":"The values you intend to send with."}},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"note":{},"status":{},"template_id":{},"would_send":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.template_create","description":"Create an email template for this company. Use {{variable}} placeholders in the subject and body. `variables` optionally declares TYPES — {\"amount\": {\"type\": \"number\"}, \"nickname\": {\"required\": false}} — with types string, number, integer, boolean, email, url, date. Anything in the body but not declared is still required: an undeclared placeholder with no value is the hole a send now refuses to ship.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"subject":{"type":"string","minLength":1},"html_content":{"type":"string","minLength":1},"text_content":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"variables":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","subject","html_content"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"status":{},"undeclared_placeholders":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.template_get","description":"One email template in full — subject, HTML and text bodies, category, and each variable with its type, whether it is required, and whether it was actually declared. A variable present in the body but never declared is still REQUIRED, because an unfilled placeholder is visible to the recipient.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"integer","minimum":1}},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-get","http_method":"POST","dispatch_endpoint":null},{"name":"email.template_list","description":"This company's own email templates, each with the variables it actually needs. ⛔ The variable list is read from the template BODY, not from its stored declaration — the two drift, and the body is what gets substituted. Filter by category; inactive templates are hidden unless you ask. These are the merchant's templates; Solid#'s own transactional mail (invoices, payment links) is separate and not editable here.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","nullable":true},"include_inactive":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"note":{},"status":{},"templates":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.template_preview","description":"See what a customer would see: renders the template with your values and returns the result. ⛔ A TEST NEVER GOES TO A CUSTOMER — the only permitted recipient is the calling company's own account address, and naming anyone else is refused. It renders and returns rather than handing anything to a mail provider, because the real send path owns suppression, logging and billing and a test must not go around it. Refuses outright if the template cannot render.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"integer","minimum":1},"variables":{"type":"object","nullable":true},"to":{"type":"string","nullable":true,"description":"Optional and must equal your own address; anything else is refused."}},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"test_send_recipient_refused","when":"A test send goes only to the company's own address (the email of its first user).","override":null,"code_in_response":true},{"code":"no_company_address","when":"No user of the company has an email to test-send to.","override":null,"code_in_response":false},{"code":"template_not_renderable","when":"The variables leave a required placeholder missing or wrongly typed.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-preview","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"note":{},"preview_html":{},"sent":{},"status":{},"subject":{},"would_send_to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email.template_update","description":"Change an email template. Only the fields you pass are touched — omit a field to leave it alone. Set is_active=false to retire a template without deleting it, so anything that referenced it can still be explained.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"html_content":{"type":"string","nullable":true},"text_content":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"variables":{"type":"object","nullable":true},"is_active":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"642","noun":"email_template","acts_on":{"noun":"email_template","address":"642","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/email/template-update","http_method":"POST","dispatch_endpoint":null},{"name":"email_attachment_download","description":"Download a single attachment from a message. Returns base64 data + size + mime. Provider-agnostic.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_id":{"type":"string"},"attachment_id":{"type":"string"},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_id","attachment_id"]},"required_scope":"comms:read","transport":"dispatch","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"mailbox.attachment_download","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"attachment":{},"preflight":{},"provider":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email_list_unread","description":"List only unread messages. Convenience wrapper for email_read_recent(unread_only=True).","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"comms:read","transport":"dispatch","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"mailbox.list_unread","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"email_read_recent","description":"List recent inbox messages for triage. Provider-agnostic — routes through whichever inbox the company has connected (Gmail / Outlook / IMAP). Returns metadata + snippets only, no full bodies. Use email_thread_get for full content.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max messages. Default 25."},"unread_only":{"type":"boolean","description":"If true, only unread. Default false."},"query":{"type":"string","description":"Optional provider-native search query (Gmail q syntax, Outlook $filter, etc.)"},"provider":{"type":"string","description":"Optional provider override when the company has multiple inboxes."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"comms:read","transport":"dispatch","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"mailbox.read_recent","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"limit":{},"messages":{},"preflight":{},"provider":{},"returned_count":{},"status":{},"unread_only":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email_send","description":"Send an email to one or a small list of recipients. Runs email.send: the FROM identity comes from the company's email lane (its connected mailbox or custom domain). Use for one-off transactional emails or short outreach (booking confirmations, follow-ups, introductions). For bulk campaigns or drip sequences delegate to Marcus / the marketing automation system.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string"},"description":"Recipient email addresses. Max 5 per call.","minItems":1,"maxItems":5},"subject":{"type":"string","description":"Subject line. 1–200 chars.","minLength":1,"maxLength":200},"body":{"type":"string","description":"Email body. HTML or plain text per body_type. Max 50k chars.","minLength":1,"maxLength":50000},"body_type":{"type":"string","enum":["html","text"],"description":"Default 'html'."},"sender_name":{"type":"string","description":"Optional display name (e.g. 'Sarah from Acme Plumbing').","maxLength":100},"reply_to":{"type":"string","description":"Optional reply-to email address."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to","subject","body"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"640","noun":"email_message","acts_on":{"noun":"email_message","address":"640","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"email.send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"from_address":{},"lane":{},"message_id":{},"ok":{},"preflight":{},"provider":{},"recipients":{},"subject":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"email_thread_get","description":"Get the full content of an inbox thread (all messages). Provider-agnostic. Use the thread_id returned by email_read_recent.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["thread_id"]},"required_scope":"comms:read","transport":"dispatch","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"mailbox.thread_get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preflight":{},"provider":{},"status":{},"thread":{},"thread_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"errors.explain_recent_cascade","description":"Target error + sibling errors within ± window_minutes.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"error_id":{"type":"integer","minimum":1},"window_minutes":{"type":"integer","minimum":1,"maximum":240,"default":10}},"required":["error_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"errors","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/errors/explain-recent-cascade","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"factors":{},"narrative":{},"sibling_total":{},"siblings":{},"success":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"estimate.generate","description":"Create a branded proposal, estimate, bid or quote (PDF-ready) for this company. Set document_type to choose which. Saved as a draft with a public link; reversible. Previews unless confirm=true. Price from the catalog: find items with catalog.search and pass their product_id / service_id — name and price come from the catalog. Add hours with proposals.add_labor and a scanned supplier receipt with proposals.add_receipt_lines. ⛔ A document here is not yet money owed. To bill it — \"make an invoice\" — call proposals.convert_to_invoice on the result: that makes the real accounts-receivable invoice (invoice.list).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Document title, e.g. 'Bathroom remodel — Smith residence'."},"items":{"type":"array","description":"Line items. Each: a catalog product_id or service_id (catalog.search) — then name and unit_price come from the catalog — or name + unit_price. quantity (default 1), unit, description.","items":{"type":"object","properties":{"product_id":{"type":"integer"},"service_id":{"type":"integer"},"name":{"type":"string"},"unit_price":{"type":"number"},"quantity":{"type":"number"},"unit":{"type":"string"},"description":{"type":"string"}}}},"document_type":{"type":"string","enum":["proposal","estimate","bid","quote","invoice","plan"],"description":"Default 'proposal'. Use 'invoice' to bill, 'estimate'/'bid'/'quote' to price work."},"contact_id":{"type":"integer","description":"Customer contact id (recommended)."},"deal_id":{"type":"integer","description":"Originating deal id (optional)."},"description":{"type":"string","description":"Scope of work / description."},"tax_rate":{"type":"number","description":"Tax rate percent (0-100)."},"discount_percent":{"type":"number","description":"Discount percent (0-100)."},"due_date":{"type":"string","description":"Invoice due date (ISO). Defaults to +30d for invoices."},"valid_until":{"type":"string","description":"Proposal expiry (ISO)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","items"]},"required_scope":"ops:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/estimate/generate","http_method":"POST","dispatch_endpoint":null},{"name":"estimate.settings","description":"What a quote costs and what approving it means for this company: the labour rate, the materials markup and default tax the document builder prices with; whether the customer must give a purchase-order number, whether they must tick the terms, the terms and 'what is not included' text (or the knowledge-base category those come from), a deposit percent, and whether approval creates the order, the invoice and a payment link by itself. Call with no arguments to see the current rules. An empty string clears a text back to the default. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"require_po":{"type":"boolean","description":"The customer must give a purchase-order number to approve."},"require_terms_accept":{"type":"boolean","description":"They must tick that they read the terms."},"require_signature":{"type":"boolean","description":"Approving takes a drawn signature (on by default) — the proof it was them."},"terms_text":{"type":"string","description":"The contract shown on the quote. Empty clears it (falls back to the KB)."},"terms_kb_category":{"type":"string","description":"KB category holding the terms when no text is set. Default 'terms'."},"exclusions_text":{"type":"string","description":"What is NOT included. Empty clears it (falls back to the KB)."},"exclusions_kb_category":{"type":"string","description":"KB category for exclusions. Default 'exclusions'."},"deposit_percent":{"type":"number","description":"Ask for this much at approval, 0-100. 0 asks for the balance."},"auto_convert_on_approval":{"type":"boolean","description":"Approval creates the order."},"auto_invoice_on_approval":{"type":"boolean","description":"Approval creates the invoice."},"payment_link_on_approval":{"type":"boolean","description":"Approval creates a way to pay."},"payment_link_hours":{"type":"integer","minimum":1,"description":"How long that link stands. Default 72."},"valid_days":{"type":"integer","minimum":1,"description":"How long a quote stands when none is set on it. Default 30."},"labor_rate_per_hour":{"type":"number","minimum":0,"description":"What an hour of labour bills at ('4 hours' × this). Until set, drafts use $75 and say so."},"materials_markup_percent":{"type":"number","minimum":0,"maximum":500,"description":"Time & materials: a billed supplier-receipt line is cost × (1 + this/100). Default 0."},"default_tax_rate":{"type":"number","minimum":0,"maximum":100,"description":"Tax percent a new estimate or invoice starts with. Each document can change it."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/estimate/settings","http_method":"POST","dispatch_endpoint":null},{"name":"event.list","description":"List active event subscriptions for this tenant.","shape":"subscribe","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"event","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/event/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"subscriptions":{},"warning":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"event.poll","description":"Fetch new events for a subscription since the cursor. Advances cursor on success.","shape":"subscribe","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription_id":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":500,"default":100}},"required":["subscription_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"event","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/event/poll","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"events":{},"has_more":{},"next_cursor":{},"subscription_id":{},"subscription_status":{},"warning":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"event.subscribe","description":"Register interest in a stream of audit events. Returns subscription_id + initial cursor. Filters: types (action_type list), contact_id, deal_id. Raises if the subscription cannot be stored — it never returns an id for a subscription that was not registered.","shape":"subscribe","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"types":{"type":"array","items":{"type":"string"},"nullable":true},"contact_id":{"type":"integer","minimum":1,"nullable":true},"deal_id":{"type":"integer","minimum":1,"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"09","noun":"event","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/event/subscribe","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cursor":{},"filters":{},"polling_hint":{},"subscription_id":{},"ttl_seconds":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"event.unsubscribe","description":"Delete an event subscription by subscription_id from this tenant's Redis subscription store, ending event.poll for it. Idempotent; returns removed true or false.","shape":"subscribe","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["subscription_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"09","noun":"event","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/event/unsubscribe","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"removed":{},"subscription_id":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"expense.create","description":"Record money the business spent or owes: kind='expense' for a supplier receipt (recorded as paid), kind='bill' for a bill still owed (accounts payable). Pass intake_id from document_extract to file it straight from the paper — vendor, lines, tax, total and dates are read off it; anything you pass overrides. Optionally assign to a job (deal_id), mark billable to a customer (contact_id), set a category (materials, fuel, tools, meals, rent, software …). Records only — moves no money. Never use this for money a customer paid the business.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["expense","bill"],"default":"expense"},"intake_id":{"type":"integer","minimum":1,"description":"A Document Intake read to file from."},"vendor_name":{"type":"string","description":"Who it was from."},"amount":{"type":"number","minimum":0,"description":"The total."},"purchase_date":{"type":"string","description":"YYYY-MM-DD; default today."},"due_date":{"type":"string","description":"Bills: YYYY-MM-DD."},"items":{"type":"array","items":{"type":"object"},"description":"[{description, quantity, unit_price, line_total, sku, category, product_id}]"},"tax_amount":{"type":"number","minimum":0},"category":{"type":"string"},"payment_method":{"type":"string","enum":["card","cash","check","ach","company_card","personal_reimburse","other"]},"reference":{"type":"string","description":"The vendor's receipt or invoice number."},"deal_id":{"type":"integer","minimum":1,"description":"The job it was for."},"contact_id":{"type":"integer","minimum":1,"description":"The customer it is billable to."},"document_id":{"type":"integer","minimum":1,"description":"The receipt photo."},"is_billable":{"type":"boolean"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/create","http_method":"POST","dispatch_endpoint":null},{"name":"expense.get","description":"Accounts payable — one expense or bill with its line items, job, receipt file and accounting-sync status.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1}},"required":["purchase_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/get","http_method":"POST","dispatch_endpoint":null},{"name":"expense.list","description":"Accounts payable — the company's expenses (money already spent, e.g. supplier receipts) and bills (money owed), newest first. Filter by kind (expense|bill), status (draft|posted|paid|void), vendor, job (deal_id) or date range. Amounts come as dollars and exact cents.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["expense","bill"]},"status":{"type":"string","enum":["draft","posted","paid","void"]},"vendor_id":{"type":"integer"},"deal_id":{"type":"integer"},"since":{"type":"string","description":"YYYY-MM-DD"},"until":{"type":"string","description":"YYYY-MM-DD"},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50},"offset":{"type":"integer","minimum":0,"default":0}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/list","http_method":"POST","dispatch_endpoint":null},{"name":"expense.mark_paid","description":"Record that a bill (accounts payable) was paid — when, how, and the check or confirmation number. Records the fact only; it does not pay anyone.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"paid_at":{"type":"string","description":"YYYY-MM-DD; default today."},"payment_method":{"type":"string","enum":["card","cash","check","ach","company_card","personal_reimburse","other"]},"reference":{"type":"string","description":"Check or confirmation number."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id"]},"required_scope":"payments:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/mark-paid","http_method":"POST","dispatch_endpoint":null},{"name":"expense.payables","description":"Accounts payable aging — every open bill, bucketed by how overdue it is (not due, 1–30, 31–60, 61–90, 90+ days, no due date), the total owed, and the next bills due.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"as_of":{"type":"string","description":"YYYY-MM-DD; default today"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/payables","http_method":"POST","dispatch_endpoint":null},{"name":"expense.summary","description":"Accounts payable — money out over a period, grouped by category, vendor, kind or job (deal). Paid and owed are reported separately, never added together. Pass deal_id for one job's costs (materials against the job's revenue).","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string"},"until":{"type":"string"},"group_by":{"type":"string","enum":["category","vendor","kind","deal"],"default":"category"},"deal_id":{"type":"integer"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/summary","http_method":"POST","dispatch_endpoint":null},{"name":"expense.sync","description":"Send expenses and bills to the connected accounting system (QuickBooks, Xero or FreshBooks). With purchase_id it sends that one now and says how it landed: synced, pending (waiting on something real, like a FreshBooks bill not yet paid) or failed with the reason. Without it, everything not yet in the books is queued and each purchase shows its own status (expense.get). Never enters the same purchase twice.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/sync","http_method":"POST","dispatch_endpoint":null},{"name":"expense.update","description":"Assign an expense or bill to a job (deal_id) or a customer (contact_id), set its category, mark it billable, change its due date, reference or notes. The amount and vendor cannot change — void it and file it again.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"deal_id":{"type":"integer","minimum":1},"contact_id":{"type":"integer","minimum":1},"category":{"type":"string"},"is_billable":{"type":"boolean"},"due_date":{"type":"string"},"reference":{"type":"string"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id"]},"required_scope":"payments:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_editable","when":"Only deal_id, contact_id, category, is_billable, notes, due_date or reference can change — void and re-file for amount or vendor.","override":null,"code_in_response":true},{"code":"purchase_void","when":"The purchase is void (checked at execution, not in the preview).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/update","http_method":"POST","dispatch_endpoint":null},{"name":"expense.void","description":"Void an expense or bill that was filed by mistake, with the reason. It stays on record as void — nothing is deleted.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"reason":{"type":"string","minLength":3,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id","reason"]},"required_scope":"payments:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/expense/void","http_method":"POST","dispatch_endpoint":null},{"name":"expense_create","description":"Record money the business spent or owes: kind='expense' for a supplier receipt (recorded as paid), kind='bill' for a bill still owed (accounts payable). Pass intake_id from document_extract to file it straight from the paper — vendor, lines, tax, total and dates are read off it; anything you pass overrides. Optionally assign to a job (deal_id), mark billable to a customer (contact_id), set a category (materials, fuel, tools, meals, rent, software …). Records only — moves no money. Never use this for money a customer paid the business.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["expense","bill"],"default":"expense"},"intake_id":{"type":"integer","minimum":1,"description":"A Document Intake read to file from."},"vendor_name":{"type":"string","description":"Who it was from."},"amount":{"type":"number","minimum":0,"description":"The total."},"purchase_date":{"type":"string","description":"YYYY-MM-DD; default today."},"due_date":{"type":"string","description":"Bills: YYYY-MM-DD."},"items":{"type":"array","items":{"type":"object"},"description":"[{description, quantity, unit_price, line_total, sku, category, product_id}]"},"tax_amount":{"type":"number","minimum":0},"category":{"type":"string"},"payment_method":{"type":"string","enum":["card","cash","check","ach","company_card","personal_reimburse","other"]},"reference":{"type":"string","description":"The vendor's receipt or invoice number."},"deal_id":{"type":"integer","minimum":1,"description":"The job it was for."},"contact_id":{"type":"integer","minimum":1,"description":"The customer it is billable to."},"document_id":{"type":"integer","minimum":1,"description":"The receipt photo."},"is_billable":{"type":"boolean"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"dispatch","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"expense.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preview":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"expense_sync","description":"Send expenses and bills to the connected accounting system (QuickBooks, Xero or FreshBooks). With purchase_id it sends that one now and says how it landed: synced, pending (waiting on something real, like a FreshBooks bill not yet paid) or failed with the reason. Without it, everything not yet in the books is queued and each purchase shows its own status (expense.get). Never enters the same purchase twice.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"dispatch","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"expense.sync","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"accounting_sync_status":{},"amount":{},"next":{},"preview":{},"provider":{},"purchase_id":{},"purchase_ids":{},"queued":{},"vendor":{},"waiting":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"expense_update","description":"Assign an expense or bill to a job (deal_id) or a customer (contact_id), set its category, mark it billable, change its due date, reference or notes. The amount and vendor cannot change — void it and file it again.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"deal_id":{"type":"integer","minimum":1},"contact_id":{"type":"integer","minimum":1},"category":{"type":"string"},"is_billable":{"type":"boolean"},"due_date":{"type":"string"},"reference":{"type":"string"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"expense.update","status":"active","inverse":null,"refuses_when":[{"code":"not_editable","when":"Only deal_id, contact_id, category, is_billable, notes, due_date or reference can change — void and re-file for amount or vendor.","override":null,"code_in_response":true},{"code":"purchase_void","when":"The purchase is void (checked at execution, not in the preview).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preview":{},"purchase_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"expense_void","description":"Void an expense or bill that was filed by mistake, with the reason. It stays on record as void — nothing is deleted.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"purchase_id":{"type":"integer","minimum":1},"reason":{"type":"string","minLength":3,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["purchase_id","reason"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"expense.void","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount":{},"preview":{},"purchase_id":{},"vendor":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"faq.analyze","description":"Analyze customer interactions and suggest FAQ entries.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"max_suggestions":{"type":"integer","minimum":1,"maximum":50,"default":10}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"88","noun":"faq","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/faq/analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"message":{},"ok":{},"reason":{},"status":{},"suggestions":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"faq.approve","description":"Approve an auto-generated FAQ suggestion — creates a published KB article.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"suggestion_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["suggestion_id"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"88","noun":"faq","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/faq/approve","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"article_id":{},"status":{},"suggestion_id":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"fee.adjust","description":"Reduce a charged fee to a lower amount. Downward only — never bills more.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"fee_id":{"type":"integer","minimum":1},"new_amount":{"type":"number","minimum":0},"reason":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","fee_id","new_amount","reason"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/adjust","http_method":"POST","dispatch_endpoint":null},{"name":"fee.check_waiver_eligibility","description":"Check whether a fee may be waived under THIS company's configured waiver rules. A company with no waiver policy configured is told so and grants nothing — silence is never read as permission.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"fee_id":{"type":"integer","minimum":1}},"required":["contact_id","fee_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/check-waiver-eligibility","http_method":"POST","dispatch_endpoint":null},{"name":"fee.explain","description":"Explain one fee: what it is, what it cost, and how this company answers the objections merchants raise about it. Description and objection responses come from THIS company's own fee schedule — if they have not configured any, none are invented.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"fee_id":{"type":"integer","minimum":1}},"required":["fee_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/explain","http_method":"POST","dispatch_endpoint":null},{"name":"fee.history","description":"Every fee charged to a contact in a period, and which of them were waived.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"months":{"type":"integer","minimum":1,"maximum":60,"default":12},"fee_code":{"type":"string","nullable":true}},"required":["contact_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/history","http_method":"POST","dispatch_endpoint":null},{"name":"fee.summary","description":"Totals charged, waived and outstanding for one contact over a period.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"months":{"type":"integer","minimum":1,"maximum":60,"default":12}},"required":["contact_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/summary","http_method":"POST","dispatch_endpoint":null},{"name":"fee.waive","description":"Waive a fee. Re-checks eligibility against the company's policy before writing — the caller's own check is never taken on trust.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"fee_id":{"type":"integer","minimum":1},"reason":{"type":"string","minLength":1},"waived_by":{"type":"string","default":"agent"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","fee_id","reason"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"552","noun":"account_fee","acts_on":{"noun":"account_fee","address":"552","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fee/waive","http_method":"POST","dispatch_endpoint":null},{"name":"field.create","description":"Define a custom field on contacts, customers, deals or leads. `name` is the internal key (snake_case); `label` is what a human sees.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"field_type":{"type":"string","default":"text"},"entity_type":{"type":"string","default":"contact"},"label":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"09","noun":"field","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/field/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"entity_type":{},"field_id":{},"field_type":{},"label":{},"name":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"field.list","description":"Lists the tenant's custom field definitions (company_field_schemas), optionally for one entity_type such as contact, customer, deal or lead. Returns id, key, label, type and options per field.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"entity_type":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"field","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/field/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"fields":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"field.update","description":"Updates a custom field definition (company_field_schemas, by field_id): label, field_type and/or options. Returns the list of updated fields, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"field_id":{"type":"integer","minimum":1},"label":{"type":"string","nullable":true},"field_type":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["field_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"09","noun":"field","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/field/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"field_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"file.create_folder","description":"Creates a folder in the tenant's file browser (folders table), optionally nested under parent_id. Requires name; returns the new folder_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"parent_id":{"nullable":true,"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"84","noun":"file","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/file/create-folder","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"folder_id":{},"name":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"file.delete","description":"Deletes a file-browser entry by file_id; the same documents row storage.delete removes. Only the database row is deleted, not the stored object. Returns deleted or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"84","noun":"file","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/file/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"file_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"file.search","description":"Search the file browser by filename or tag. Same company-scoped document query as storage.search (the file browser is Document-backed). A blank query is refused, never answered with an empty list.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":1},"limit":{"type":"integer","minimum":1,"maximum":200,"default":20}},"required":["query"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"84","noun":"file","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/file/search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"query":{},"results":{},"status":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"file.share","description":"Grant someone access to a file — NOT implemented; always raises. Nothing writes the DocumentShare table, so no grant can be recorded. Drive-backed sharing lives at POST /api/v1/files/share (Drive file id + Drive role).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"integer"},"share_with":{"type":"string"},"permission":{"type":"string","default":"view"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id","share_with"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"84","noun":"file","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/file/share","http_method":"POST","dispatch_endpoint":null},{"name":"file.upload","description":"Upload a file into the file browser, optionally into one of its folders (folder_id from file.create_folder). Send the bytes base64-encoded in content_base64. Runs storage.upload.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1},"content_base64":{"type":"string","minLength":1},"folder_id":{"nullable":true,"type":"integer"},"content_type":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content_base64","filename"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"84","noun":"file","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/file/upload","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flow.activate","description":"Make a commerce flow live. Same operation as flows.activate.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.activate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/activate","http_method":"POST","dispatch_endpoint":null},{"name":"flow.archive","description":"Archive a commerce flow. Same operation as flows.archive.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.archive","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/archive","http_method":"POST","dispatch_endpoint":null},{"name":"flow.clone","description":"Copy a commerce flow onto a new draft. Same operation as flows.clone.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"new_name":{"nullable":true,"type":"string"},"new_price":{"nullable":true,"type":"number"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.clone","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/clone","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flow.create","description":"Create a commerce flow. Same operation as flows.create.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"flow_type":{"nullable":true,"type":"string","description":"Same as commerce_type: one_time, recurring or free."},"description":{"nullable":true,"type":"string"},"commerce_type":{"type":"string","default":"one_time"},"product_name":{"nullable":true,"type":"string"},"price":{"type":"number","default":0},"currency":{"type":"string","default":"USD"},"interval":{"nullable":true,"type":"string"},"trial_days":{"nullable":true,"type":"integer"},"capture":{"nullable":true,"type":"object"},"automation":{"nullable":true,"type":"object"},"template_source":{"nullable":true,"type":"string"},"ai_prompt":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flow.list","description":"List commerce flows. Same operation as flows.list.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"nullable":true,"type":"string"},"commerce_type":{"nullable":true,"type":"string"},"limit":{"type":"integer","default":50},"skip":{"type":"integer","default":0}},"additionalProperties":true},"required_scope":"flows:read","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/list","http_method":"POST","dispatch_endpoint":null},{"name":"flow.pause","description":"Pause a live commerce flow. Same operation as flows.pause.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.pause","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/pause","http_method":"POST","dispatch_endpoint":null},{"name":"flow.test","description":"Move a commerce flow to testing mode so its checkout runs against sandbox payments. Same operation as flows.test.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"test_data":{"nullable":true,"type":"object","description":"Not supported; refused if given."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.test","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/test","http_method":"POST","dispatch_endpoint":null},{"name":"flow.update","description":"Update a commerce flow's editable fields. Same operation as flows.update.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["integer","string"]},"name":{"nullable":true,"type":"string"},"description":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"01","noun":"flow","location":"svc.api","same_as":"flows.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flow/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.activate","description":"Sets a Commerce Flow (commerce_flows) live by flow_id (public id or integer id) and stamps activated_at. Refuses an archived flow. Returns the flow_id and status live.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"flow_archived","when":"The flow is archived.","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/activate","http_method":"POST","dispatch_endpoint":null},{"name":"flows.add_agent","description":"Appends an agent action (agent_type, agent_id, trigger, action, optional delay/condition/config) to a Commerce Flow's automation.agents list in commerce_flows. Needs the public flow_id. Returns the new action_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"agent_type":{"type":"string"},"agent_id":{"type":"integer"},"trigger":{"type":"string"},"action":{"type":"string"},"delay":{"type":"string"},"condition":{"type":"string"},"config":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["action","agent_id","agent_type","flow_id","trigger"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/add-agent","http_method":"POST","dispatch_endpoint":null},{"name":"flows.archive","description":"Sets a Commerce Flow (commerce_flows) to archived by flow_id; an archived flow can no longer be activated. Nothing is deleted. Returns the flow_id and status archived.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/archive","http_method":"POST","dispatch_endpoint":null},{"name":"flows.clone","description":"Copies a Commerce Flow (commerce_flows) within the tenant by flow_id, keeping product, pricing, capture and automation; optional new_name and new_price. Returns the new flow as a draft copy.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"new_name":{"type":"string"},"new_price":{"type":"number"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/clone","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.create","description":"Creates a Commerce Flow (commerce_flows: a sellable product with checkout and automation) from a name, with optional commerce_type, product_name, price, currency, interval and trial_days. Returns the new flow.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"commerce_type":{"type":"string"},"product_name":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string"},"interval":{"type":"string"},"trial_days":{"type":"integer"},"capture":{"type":"object"},"automation":{"type":"object"},"template_source":{"type":"string"},"ai_prompt":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.dispatch_event","description":"Manually dispatch a Flow event (for testing).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"event_type":{"type":"string"},"event_data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["event_type","flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/dispatch-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"dispatched_tasks":{},"error":{},"success":{},"task_ids":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.get","description":"Reads one Commerce Flow (commerce_flows) by flow_id, accepting the public string id or the integer id scoped to the tenant. Returns the full flow record.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"}},"required":["flow_id"]},"required_scope":"flows:read","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.list","description":"Lists the tenant's Commerce Flows (commerce_flows), newest first, filterable by status and commerce_type with limit/skip. Returns the flows and a total count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string"},"commerce_type":{"type":"string"},"limit":{"type":"integer"},"skip":{"type":"integer"}}},"required_scope":"flows:read","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/list","http_method":"POST","dispatch_endpoint":null},{"name":"flows.list_agents","description":"Reads the agent actions configured on one Commerce Flow (the automation.agents list in commerce_flows) by flow_id. Returns each action's id, agent, trigger, action and config.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"}},"required":["flow_id"]},"required_scope":"flows:read","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/list-agents","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agents":{},"error":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.metrics","description":"Reads Commerce Flow performance from commerce_flows counters: views, captures, conversions, revenue and conversion rate. With flow_id returns one flow; without it returns every flow of the tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"}}},"required_scope":"flows:read","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/metrics","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"metrics":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"flows.pause","description":"Sets a Commerce Flow (commerce_flows) to paused by flow_id so it stops running until activated again. Returns the flow_id and status paused.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/pause","http_method":"POST","dispatch_endpoint":null},{"name":"flows.remove_agent","description":"Removes one agent action, by action_id, from a Commerce Flow's automation.agents list in commerce_flows. Needs the public flow_id. Returns how many agent actions remain.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"action_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["action_id","flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/remove-agent","http_method":"POST","dispatch_endpoint":null},{"name":"flows.test","description":"Move a Flow to testing mode (sandbox payments).","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/test","http_method":"POST","dispatch_endpoint":null},{"name":"flows.update","description":"Update a Commerce Flow's editable fields. Status changes use flows.activate / pause / archive / test.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"flow_id":{"type":["string","integer"]},"name":{"type":"string"},"description":{"type":"string"},"product_name":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string"},"interval":{"type":"string"},"trial_days":{"type":"integer"},"capture":{"type":"object"},"commerce_config":{"type":"object"},"automation":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["flow_id"]},"required_scope":"flows:write","transport":"http","coordinate":"09","noun":"flows","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/flows/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"flow":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.capture","description":"Record ONE answer from whichever channel produced it (voice, web, sms, chat, email). Held against the cross-channel session so a respondent can correct themselves; survey.submit is the lock-in.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"question_id":{"type":"string"},"value":{"type":["string","number","boolean","array","null"]},"provider":{"type":"string","default":"native"},"channel":{"type":"string","default":"voice"},"session_ref":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id","question_id","value"],"additionalProperties":true},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/capture","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"answered_count":{},"channel":{},"form_id":{},"question_id":{},"session_ref":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.configure_trigger","description":"Set which form this business sends at one moment, and turn it on. Validated at WRITE time: an unknown event would be stored happily and never fire, and a provider they have not connected is a form that can never be delivered — both are reported here while whoever is configuring can still fix them.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"event":{"type":"string"},"form_id":{"type":"string","nullable":true},"provider":{"type":"string","default":"native"},"enabled":{"type":"boolean","default":true},"stage":{"type":"string","nullable":true},"prompt":{"type":"string","nullable":true},"channel":{"type":"string","default":"sms"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["event"],"additionalProperties":true},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/configure-trigger","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.context","description":"Everything an agent may use while a merchant's CUSTOMER answers their form: the tenant's PUBLIC KB, their industry vocabulary, and the offers they have actually configured. ⛔ Never SKB — the respondent has no relationship with Solid# and SKB is our own internal coaching with no tenant scoping.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","default":""},"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"},"subtotal":{"type":"number","nullable":true}},"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/context","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.create","description":"Create a lead-capture form for this company. `fields` is a list of field definitions (each e.g. {\"name\":\"email\",\"label\":\"Email\",\"type\":\"email\",\"required\":true}). Returns the new form id.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","maxLength":256,"description":"Internal form name."},"fields":{"type":"array","items":{"type":"object"},"description":"Field definitions (name, label, type, required)."},"title":{"type":"string","maxLength":512,"description":"Heading shown above the form."},"site_id":{"type":"integer","description":"Optional site to attach the form to."},"submit_button_text":{"type":"string","maxLength":100,"description":"Default 'Submit'."},"success_message":{"type":"string","description":"Shown after a successful submit."},"auto_create_contact":{"type":"boolean","description":"Create a CRM contact per submission. Default true."},"default_lead_source":{"type":"string","description":"Lead source tag. Default 'Website Form'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","fields"]},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/create","http_method":"POST","dispatch_endpoint":null},{"name":"form.describe","description":"The questions of one form, exactly as a respondent meets them — prompt, kind, choices, order. No points, branches or answer keys ever ride along; scoring is server-side only. Read-only; safe to call whenever.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"provider":{"type":"string","default":"native"}},"required":["form_id"],"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/describe","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.for_event","description":"Is there a form to send at this moment? Call it after booking an appointment, closing a deal, starting onboarding or ending a call. Returns the tenant's configured form and whether it goes BEFORE the thing (intake, medical history, FAQ) or AFTER it (feedback, review). \"No form\" is the common answer and is not an error. Read-only, safe every turn.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"event":{"type":"string","default":"call_ended"}},"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/for-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.get","description":"Get one lead-capture form by id — its fields, title, messages, and settings. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."}},"required":["form_id"]},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/get","http_method":"POST","dispatch_endpoint":null},{"name":"form.lead_forms","description":"List this company's lead-capture forms (id, name, active state, submission count). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","description":"Include inactive forms. Default false."}}},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/lead-forms","http_method":"POST","dispatch_endpoint":null},{"name":"form.list","description":"List the forms available on one connected provider.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider":{"type":"string","default":"native"},"page":{"type":"integer","default":1},"per_page":{"type":"integer","default":50}},"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"forms":{},"provider":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.next_question","description":"The next unanswered question for an in-progress response — how a survey started on the web is resumed by voice, SMS or chat without the respondent repeating anything. Read-only; safe to call every turn.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"provider":{"type":"string","default":"native"},"answered":{"type":"array","items":{"type":"string"},"nullable":true},"session_ref":{"type":"string","nullable":true}},"required":["form_id"],"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/next-question","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"answered_count":{},"complete":{},"form_id":{},"next_question":{},"provider":{},"remaining_count":{},"status":{},"summary":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.responses","description":"What people actually answered. Provider-agnostic — SurveyMonkey responses and our own come back in the same shape. Answers only, no internal ids or plumbing; `channels` shows how each response was really given, which is the cross-channel premise made visible.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"provider":{"type":"string","default":"native"},"limit":{"type":"integer","default":25},"page":{"type":"integer","default":1}},"required":["form_id"],"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/responses","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"form_id":{},"provider":{},"responses":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.send","description":"Text someone the form their tenant configured for THIS moment — after a call, before an appointment, on a won deal, at onboarding. Both the provider and which form fires at which event come from the company's own settings, so this verb names neither. Wording renders in their industry's nouns. The link is always ours, so a respondent can tap it OR text back into the same session. Returns sms_disabled while A2P registration is outstanding — read the status, a returned object is not a delivered text.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_phone":{"type":"string"},"event":{"type":"string","default":"call_ended"},"contact_id":{"type":"integer","nullable":true},"call_id":{"type":"integer","nullable":true},"appointment_id":{"type":"integer","nullable":true},"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"},"base_url":{"type":"string","default":""},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to_phone"],"additionalProperties":true},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.sources","description":"Which form providers this merchant has connected (native is always on).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/sources","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"available":{},"connected":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.submissions","description":"List submissions for one lead-capture form (newest first) — the leads it captured, with contact, email, phone, and submitted data. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max rows. Default 25."}},"required":["form_id"]},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/submissions","http_method":"POST","dispatch_endpoint":null},{"name":"form.submit","description":"Finish the response and write it BACK to the provider — the half that makes a third-party form platform a partner rather than a competitor. SurveyMonkey requires collector_id; native ignores it. Pass any respondent identity you know (name/email/phone): a known contact gets this response on their CRM timeline, an unknown one with an email or phone becomes a new lead.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"provider":{"type":"string","default":"native"},"session_ref":{"type":"string","nullable":true},"collector_id":{"type":"string","nullable":true},"respondent_name":{"type":"string","nullable":true},"respondent_email":{"type":"string","nullable":true},"respondent_phone":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id"],"additionalProperties":true},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/submit","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.triggers","description":"Every moment this business could send a form, and what it does today — including the events it is NOT using, so a model can suggest them rather than guess at names. The read to make before configuring anything.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"forms:read","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/triggers","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form.update","description":"Update a lead-capture form. Pass only the fields to change (omit the rest). Set is_active=false to disable the form.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."},"name":{"type":"string","maxLength":256},"fields":{"type":"array","items":{"type":"object"}},"title":{"type":"string","maxLength":512},"submit_button_text":{"type":"string","maxLength":100},"success_message":{"type":"string"},"auto_create_contact":{"type":"boolean"},"default_lead_source":{"type":"string"},"is_active":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id"]},"required_scope":"forms:write","transport":"http","coordinate":"72","noun":"form","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/form/update","http_method":"POST","dispatch_endpoint":null},{"name":"form_create","description":"Create a lead-capture form for this company. `fields` is a list of field definitions (each e.g. {\"name\":\"email\",\"label\":\"Email\",\"type\":\"email\",\"required\":true}). Returns the new form id.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","maxLength":256,"description":"Internal form name."},"fields":{"type":"array","items":{"type":"object"},"description":"Field definitions (name, label, type, required)."},"title":{"type":"string","maxLength":512,"description":"Heading shown above the form."},"site_id":{"type":"integer","description":"Optional site to attach the form to."},"submit_button_text":{"type":"string","maxLength":100,"description":"Default 'Submit'."},"success_message":{"type":"string","description":"Shown after a successful submit."},"auto_create_contact":{"type":"boolean","description":"Create a CRM contact per submission. Default true."},"default_lead_source":{"type":"string","description":"Lead source tag. Default 'Website Form'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","fields"]},"required_scope":"forms:write","transport":"dispatch","coordinate":"72","noun":"form","location":"svc.api","same_as":"form.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"form_get","description":"Get one lead-capture form by id — its fields, title, messages, and settings. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."}},"required":["form_id"]},"required_scope":"forms:read","transport":"dispatch","coordinate":"72","noun":"form","location":"svc.api","same_as":"form.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"auto_create_contact":{},"default_lead_source":{},"description":{},"fields":{},"form_id":{},"found":{},"submit_button_text":{},"success_message":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form_submissions","description":"List submissions for one lead-capture form (newest first) — the leads it captured, with contact, email, phone, and submitted data. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max rows. Default 25."}},"required":["form_id"]},"required_scope":"forms:read","transport":"dispatch","coordinate":"72","noun":"form","location":"svc.api","same_as":"form.submissions","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"form_id":{},"submissions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"form_update","description":"Update a lead-capture form. Pass only the fields to change (omit the rest). Set is_active=false to disable the form.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer","description":"lead_forms.id (from forms_list)."},"name":{"type":"string","maxLength":256},"fields":{"type":"array","items":{"type":"object"}},"title":{"type":"string","maxLength":512},"submit_button_text":{"type":"string","maxLength":100},"success_message":{"type":"string"},"auto_create_contact":{"type":"boolean"},"default_lead_source":{"type":"string"},"is_active":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id"]},"required_scope":"forms:write","transport":"dispatch","coordinate":"72","noun":"form","location":"svc.api","same_as":"form.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"forms_list","description":"List this company's lead-capture forms (id, name, active state, submission count). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","description":"Include inactive forms. Default false."}}},"required_scope":"forms:read","transport":"dispatch","coordinate":"79","noun":"forms","location":"svc.api","same_as":"form.lead_forms","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"forms":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"fulfillment.get_settings","description":"Fulfillment — how this business gets goods to a buyer: in-store pickup (and how soon it is ready), local delivery (radius and days) and shipping (days). These are the only delivery or pickup times an outside AI shopping for a customer is ever told; unset means buyers are told to ask.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"49","noun":"fulfillment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fulfillment/get-settings","http_method":"POST","dispatch_endpoint":null},{"name":"fulfillment.update_settings","description":"Fulfillment — set what this business promises buyers: pickup on/off and ready-within hours, local delivery on/off with radius (km) and days, shipping on/off with minimum and maximum days. Shows exactly what a buyer's AI will be told, and updates the business's marketplace listings to match.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"pickup":{"type":"boolean"},"pickup_ready_hours":{"type":"integer","minimum":0},"local_delivery":{"type":"boolean"},"local_delivery_km":{"type":"number","minimum":0},"local_delivery_days":{"type":"integer","minimum":0},"shipping":{"type":"boolean"},"ship_days_min":{"type":"integer","minimum":0},"ship_days_max":{"type":"integer","minimum":0},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"49","noun":"fulfillment","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/fulfillment/update-settings","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"marketplace_listings_updated":{},"message":{},"problems":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"gdpr.delete_contact","description":"Permanently delete a contact under GDPR Article 17 / right to be forgotten. Hard-deletes from crm_contacts plus all pure-PII child tables (notes, tags, conversation rows, segment memberships). NULLs the contact_id on tables that must be retained for legal/financial reasons (deals, tasks, voice_calls, appointments, orders, invoices). OWNER role + typed-phrase 'DELETE CONTACT {id} PERMANENTLY' required to execute. Logs a governance audit row with the contact's id + a hash of the deleted PII for downstream verification.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"ID of the contact to delete. Must belong to this company."},"reason":{"type":"string","description":"Plain-English reason for the deletion (will be stored in the audit log). E.g. 'GDPR request via email 2026-05-21'.","minLength":1,"maxLength":1000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","reason"]},"required_scope":"gdpr:write","transport":"http","coordinate":"23","noun":"gdpr","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gdpr/delete-contact","http_method":"POST","dispatch_endpoint":null},{"name":"gdpr.delete_data","description":"GDPR Art.17 erasure — NOT executable from an agent surface; always raises. Irreversible, needs a verified confirmation code. Use POST /api/v1/security/gdpr/delete.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"nullable":true,"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"gdpr:write","transport":"http","coordinate":"23","noun":"gdpr","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gdpr/delete-data","http_method":"POST","dispatch_endpoint":null},{"name":"gdpr.export_data","description":"GDPR Art.20 — export a platform USER's data (subject is user_id, not a CRM contact). Contact-level export is not implemented and raises.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"nullable":true,"type":"integer","description":"Not supported — raises NotImplementedError."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"gdpr:write","transport":"http","coordinate":"23","noun":"gdpr","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gdpr/export-data","http_method":"POST","dispatch_endpoint":null},{"name":"gdpr.update_consent","description":"GDPR Art.7 processing consent — NOT implemented; always raises (no consent store exists). For TCPA voice/SMS consent use set_contact_consent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"consent_type":{"type":"string"},"granted":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","consent_type","granted"],"additionalProperties":true},"required_scope":"gdpr:write","transport":"http","coordinate":"23","noun":"gdpr","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gdpr/update-consent","http_method":"POST","dispatch_endpoint":null},{"name":"gdpr_delete_contact","description":"Permanently delete a contact under GDPR Article 17 / right to be forgotten. Hard-deletes from crm_contacts plus all pure-PII child tables (notes, tags, conversation rows, segment memberships). NULLs the contact_id on tables that must be retained for legal/financial reasons (deals, tasks, voice_calls, appointments, orders, invoices). OWNER role + typed-phrase 'DELETE CONTACT {id} PERMANENTLY' required to execute. Logs a governance audit row with the contact's id + a hash of the deleted PII for downstream verification.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"ID of the contact to delete. Must belong to this company."},"reason":{"type":"string","description":"Plain-English reason for the deletion (will be stored in the audit log). E.g. 'GDPR request via email 2026-05-21'.","minLength":1,"maxLength":1000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","reason"]},"required_scope":"gdpr:write","transport":"dispatch","coordinate":"23","noun":"gdpr","location":"svc.api","same_as":"gdpr.delete_contact","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"contact":{},"contact_id":{},"deleted_at":{},"hard_deleted":{},"message":{},"nulled_out":{},"pii_hash":{},"preflight":{},"reason":{},"status":{},"tables_to_hard_delete":{},"tables_to_null_out":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"generate_proposal","description":"Create a branded proposal, estimate, bid or quote (PDF-ready) for this company. Set document_type to choose which. Saved as a draft with a public link; reversible. Previews unless confirm=true. Price from the catalog: find items with catalog.search and pass their product_id / service_id — name and price come from the catalog. Add hours with proposals.add_labor and a scanned supplier receipt with proposals.add_receipt_lines. ⛔ A document here is not yet money owed. To bill it — \"make an invoice\" — call proposals.convert_to_invoice on the result: that makes the real accounts-receivable invoice (invoice.list).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Document title, e.g. 'Bathroom remodel — Smith residence'."},"items":{"type":"array","description":"Line items. Each: a catalog product_id or service_id (catalog.search) — then name and unit_price come from the catalog — or name + unit_price. quantity (default 1), unit, description.","items":{"type":"object","properties":{"product_id":{"type":"integer"},"service_id":{"type":"integer"},"name":{"type":"string"},"unit_price":{"type":"number"},"quantity":{"type":"number"},"unit":{"type":"string"},"description":{"type":"string"}}}},"document_type":{"type":"string","enum":["proposal","estimate","bid","quote","invoice","plan"],"description":"Default 'proposal'. Use 'invoice' to bill, 'estimate'/'bid'/'quote' to price work."},"contact_id":{"type":"integer","description":"Customer contact id (recommended)."},"deal_id":{"type":"integer","description":"Originating deal id (optional)."},"description":{"type":"string","description":"Scope of work / description."},"tax_rate":{"type":"number","description":"Tax rate percent (0-100)."},"discount_percent":{"type":"number","description":"Discount percent (0-100)."},"due_date":{"type":"string","description":"Invoice due date (ISO). Defaults to +30d for invoices."},"valid_until":{"type":"string","description":"Proposal expiry (ISO)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","items"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"estimate.generate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preflight":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"generate_website","description":"Generate (or refresh) this company's multi-page starter website from its knowledge base — homepage, services, about, FAQ, contact and more, with industry-appropriate branding and navigation. Only fills or updates Coming-Soon pages; existing real pages are left intact, so it is safe to re-run. Optionally restrict to a subset of page slugs, set a style preset, or override the industry. Reversible per page. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"style":{"type":"string","description":"Optional style preset (e.g. 'modern', 'classic', 'bold')."},"industry":{"type":"string","description":"Optional industry override; defaults to the company's industry."},"pages":{"type":"array","items":{"type":"string"},"description":"Optional subset of page slugs to generate (e.g. ['home', 'services', 'contact']). Defaults to the full set."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"pages:write","transport":"dispatch","coordinate":"79","noun":"website","location":"svc.api","same_as":"website.generate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company":{},"ok":{},"preflight":{},"would_generate":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"get_agent_inbox","description":"Read the agent_communications inbox for ADA or a specified peer agent. Returns recent messages with sender, subject, body, priority, and status. Filter by status to see only unread ('sent') or only resolved ('responded').","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Whose inbox to read. Default 'orchestrator' (ADA's own inbox)."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"status":{"type":"string","enum":["sent","read","responded","escalated"],"description":"Filter by message status. Default all."},"limit":{"type":"integer","description":"Max messages to return. Default 25, max 100.","minimum":1,"maximum":100}}},"required_scope":null,"transport":"dispatch","coordinate":"10","noun":"agent","location":"svc.api","same_as":"agent.inbox","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"messages":{},"returned_count":{},"target_agent":{},"target_agent_id":{},"unread_count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"get_block_schema","description":"Return the canonical CMS block schema — the section/block types a page body is built from, with their shapes. Call this BEFORE edit_page_content so the layout_json you write matches what the renderer expects. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"pages:read","transport":"dispatch","coordinate":"79","noun":"block","location":"svc.api","same_as":"block.schema","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"block_types":{},"motion_schema":{},"prop_notes":{},"schema":{},"type_aliases":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"get_brand_tokens","description":"Get this company's brand DESIGN tokens — colors, typography, and shape — so designs stay on-brand. (Brand voice/tone is get_brand_truth.) Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"pages:read","transport":"dispatch","coordinate":"77","noun":"brand","location":"svc.api","same_as":"brand.tokens","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"design":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.create_event","description":"Creates an event on the primary calendar of the connected Google account; attendees get a Google invite. Needs title, start_time, end_time (ISO). Returns event_id, html_link and video_link.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"start_time":{"type":"string"},"end_time":{"type":"string"},"description":{"type":"string"},"location":{"type":"string"},"attendees":{"type":"array"},"video_conference":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["end_time","start_time","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_calendar.create_event","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.create-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"attendees_count":{},"end_time":{},"event_id":{},"html_link":{},"start_time":{},"status":{},"summary":{},"video_link":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.delete_event","description":"Deletes an event by event_id from the primary calendar of the connected Google account, optionally notifying attendees. Returns {ok, deleted}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"event_id":{"type":"string"},"notify_attendees":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["event_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.delete-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deleted":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.get_availability","description":"Free/busy lookup in the connected Google Calendar for a list of emails between start_time and end_time (ISO). Returns each email's busy periods as start/end pairs.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"emails":{"type":"array"},"start_time":{"type":"string"},"end_time":{"type":"string"}},"required":["emails","end_time","start_time"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.get-availability","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.list_events","description":"List Google Calendar events in a time range, merged with local DB events.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"start_time":{"type":"string"},"end_time":{"type":"string"},"max_results":{"type":"integer"}},"required":["end_time","start_time"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.list-events","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.schedule_meeting","description":"Schedule a meeting with video conference.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"start_time":{"type":"string"},"end_time":{"type":"string"},"attendees":{"type":"array"},"description":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["attendees","end_time","start_time","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.schedule-meeting","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar.update_event","description":"Patches an existing event (event_id) on the connected Google account's primary calendar with the fields in updates, optionally notifying attendees. Returns the updated event.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"event_id":{"type":"string"},"updates":{"type":"object"},"notify_attendees":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["event_id","updates"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar.update-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.calendar_event_create","description":"Create an event on the user's primary Google Calendar. Times are ISO-8601 with timezone (e.g. 2026-06-01T15:00:00-06:00). Attendees receive a calendar invite from Google directly. Set with_meet_link=true to attach a Google Meet conferencing link. Returns a confirmation card — the event is NOT created until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Event title."},"start_time":{"type":"string","description":"ISO-8601 start (with tz)."},"end_time":{"type":"string","description":"ISO-8601 end (with tz)."},"description":{"type":"string","description":"Optional body / agenda."},"location":{"type":"string","description":"Optional location."},"attendees":{"type":"array","items":{"type":"string"},"description":"List of attendee emails (each gets a Google invite)."},"with_meet_link":{"type":"boolean","description":"Attach a Google Meet link. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","start_time","end_time"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/calendar-event-create","http_method":"POST","dispatch_endpoint":null},{"name":"google.chat.create_space","description":"Creates a space in Google Chat for the connected Google Workspace account, adding any member emails given. Needs display_name. Returns space_id and display_name.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"display_name":{"type":"string"},"description":{"type":"string"},"members":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["display_name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_chat.create_space","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/chat.create-space","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"display_name":{},"space_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.chat.send_alert","description":"Posts an alert card with a severity (info, warning, error, critical) and optional action link to a Google Chat space. Needs space_id, title, message. Returns the sent Chat message.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"severity":{"type":"string"},"action_url":{"type":"string"},"thread_key":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message","space_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/chat.send-alert","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.chat.send_card","description":"Posts a titled card with body text to a Google Chat space (space_id). card_type: notification (default), alert, report, task_update or approval_request; optional thread_key.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"card_type":{"type":"string","description":"notification (default), alert, report, task_update or approval_request."},"thread_key":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","space_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/chat.send-card","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.chat.send_message","description":"Posts a plain-text message to a Google Chat space (space_id) in the connected Workspace, optionally into a thread (thread_key). Returns message_id and thread_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"text":{"type":"string"},"thread_key":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["space_id","text"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_chat.send_message","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/chat.send-message","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"space_id":{},"status":{},"thread_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.chat.send_notification","description":"Send a notification card in Google Chat.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"icon":{"type":"string"},"action_url":{"type":"string"},"thread_key":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message","space_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_chat.send_notification","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/chat.send-notification","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"space_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.create","description":"Creates a person in the connected Google account's Contacts (not the Solid# CRM). Needs given_name; only family_name and notes are passed through — email, phone and organization are dropped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"given_name":{"type":"string"},"family_name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"organization":{"type":"string"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["given_name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.list","description":"Lists people in the connected Google account's Contacts (Google People API, not the CRM). Optional page_size. Returns contacts plus next_page_token and sync_token.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_size":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.search","description":"Searches the connected Google account's Contacts by name, email or phone (not the Solid# CRM). Needs query. Returns matching Google contacts and a count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string"},"page_size":{"type":"integer"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.sync_from_crm","description":"Pushes one CRM contact (contact_id) to the connected Google Contacts: updates the Google contact with the same email if one exists, otherwise creates it with name, email and phone.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts id of the person to push to Google."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.sync-from-crm","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action":{},"crm_contact_id":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.sync_to_crm","description":"Sync a Google Contact to CRM via LeadPipelineService (Contact + Deal + Score).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"resource_name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["resource_name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.sync-to-crm","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"deal_id":{},"error":{},"is_new_contact":{},"lead_id":{},"lead_score":{},"lead_tier":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.contacts.update","description":"Updates a Google contact identified by resource_name (people/...) in the connected Google account: given_name, family_name and notes. Returns the updated contact.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"resource_name":{"type":"string"},"given_name":{"type":"string"},"family_name":{"type":"string"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["resource_name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/contacts.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs.create","description":"Creates a new Google Doc in the connected Google Drive, with optional body text and folder_id. Needs title. Returns document_id and web_url.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"folder_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_docs.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"document_id":{},"status":{},"title":{},"web_url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs.create_from_template","description":"Create a Google Doc from a template with merge fields.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"string"},"title":{"type":"string"},"merge_fields":{"type":"object"},"folder_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["template_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs.create-from-template","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs.export_pdf","description":"Exports a Google Doc (document_id) to PDF and saves that PDF as a new file in Drive, optionally in destination_folder_id; returns the new file_id, name and link.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"string"},"destination_folder_id":{"type":"string","description":"Drive folder for the PDF; omit for My Drive root."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs.export-pdf","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"format":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs.get_content","description":"Reads a Google Doc (document_id) from the connected Google account and returns its body as plain text. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"string"}},"required":["document_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs.get-content","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs.update","description":"Update a Google Doc with batch requests.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"string"},"requests":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id","requests"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.docs_read","description":"Read the text of a Google Doc the user points to (by document id or URL) from their connected Google account. Read-only. Returns the title and plain-text content. NOTE: with the current Google scope (drive.file) this reads docs Solid# created or that the user picked via the file picker; reading an arbitrary existing doc returns a scope error with the next step — never invent the contents.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document":{"type":"string","description":"Google Doc id or full docs.google.com URL."}},"required":["document"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/docs-read","http_method":"POST","dispatch_endpoint":null},{"name":"google.drive.create_folder","description":"Creates a folder in the connected Google Drive, optionally inside parent_folder_id. Needs name. Returns the new folder's file info (id, name, link).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"parent_folder_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.create-folder","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.create_permission","description":"Adds a user permission on a Drive file or folder (file_id) for an email at the given role (reader default; commenter, writer, organizer). No notification option; returns the permission.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","description":"reader (default), commenter, writer, fileOrganizer or organizer."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["email","file_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.create-permission","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.create_shared_drive","description":"Creates a new shared drive in the connected Google Workspace account. Needs name. Returns the shared drive (id, name).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.create-shared-drive","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.delete","description":"Permanently deletes a file (file_id) from the connected Google Drive via the Drive API DELETE call, not a move to trash. Returns {ok, deleted}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deleted":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.download","description":"Downloads a file (file_id) from the connected Google Drive. Returns the file bytes base64-encoded plus size_bytes.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"}},"required":["file_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.download","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{},"size_bytes":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.list_permissions","description":"Lists who can access a Drive file or folder (file_id): each permission's type, role, email or domain and display name. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"}},"required":["file_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.list-permissions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.search","description":"Searches the connected Google Drive for non-trashed files whose name contains query, optionally within folder_id or by mime_type. Returns file info list and count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string"},"folder_id":{"type":"string"},"mime_type":{"type":"string"},"max_results":{"type":"integer"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.share","description":"Shares a Drive file (file_id) with a person's email as reader, commenter or writer, optionally emailing them a notification. Grants real access; returns the new permission.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"},"email":{"type":"string"},"role":{"type":"string","description":"reader (default), commenter or writer."},"send_notification":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["email","file_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.share","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.transfer_ownership","description":"Transfers ownership of a file (file_id) in the connected Google Drive to new_owner_email. Returns the resulting Drive permission.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"file_id":{"type":"string"},"new_owner_email":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["file_id","new_owner_email"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.transfer-ownership","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.drive.upload","description":"Uploads a file to the connected Google Drive from content_base64, optionally into folder_id with mime_type and description. Needs filename. Writes to Drive; returns file_id and link.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"filename":{"type":"string"},"content_base64":{"type":"string"},"mime_type":{"type":"string"},"folder_id":{"type":"string"},"description":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["filename"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/drive.upload","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.forms.add_question","description":"Adds a question to a Google Form (form_id) in the connected account. question_type must be an uppercase Google type such as SHORT_ANSWER or MULTIPLE_CHOICE; the lowercase default matches none. Returns the question.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"title":{"type":"string"},"question_type":{"type":"string"},"required":{"type":"boolean"},"options":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/forms.add-question","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.forms.analyze_responses","description":"Analyze responses to a Google Form with statistics.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"}},"required":["form_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/forms.analyze-responses","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.forms.create_form","description":"Creates a Google Form in the connected Google account, optionally as a quiz and collecting respondent email. Needs title. Returns the form (form_id, responder link).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"is_quiz":{"type":"boolean"},"collect_email":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/forms.create-form","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.forms.get_form","description":"Fetches a Google Form (form_id) from the connected Google account, including its settings and questions. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"}},"required":["form_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/forms.get-form","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.forms.list_responses","description":"Lists submitted responses to a Google Form (form_id) in the connected account, up to page_size. Returns the responses and a count. These are Google Forms, not Solid# forms.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"string"},"page_size":{"type":"integer"}},"required":["form_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/forms.list-responses","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.apply_labels","description":"Adds and/or removes Gmail label IDs (add_labels, remove_labels) on a list of message_ids in one batch modify; reports per-message success.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_ids":{"type":"array"},"add_labels":{"type":"array"},"remove_labels":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_ids"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.apply-labels","http_method":"POST","dispatch_endpoint":null},{"name":"google.gmail.archive","description":"Archives Gmail messages (message_ids) by removing the INBOX label in one batch; they stay searchable in All Mail. Reports per-message success.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_ids":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_ids"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.archive","http_method":"POST","dispatch_endpoint":null},{"name":"google.gmail.create_draft","description":"Creates a draft (nothing is sent) in the connected Gmail mailbox. Needs to, subject, body. Returns draft_id, message_id and thread_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":"array"},"subject":{"type":"string"},"body":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","subject","to"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_gmail.create_draft","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.create-draft","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"draft_id":{},"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.create_label","description":"Creates a label in the connected Gmail mailbox. Needs name (use / for nesting). Returns the new label with its id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.create-label","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.get_thread","description":"Fetches every message in a Gmail thread (thread_id) from the connected mailbox, with subject, recipients and decoded body. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"}},"required":["thread_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.get-thread","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.list_drafts","description":"Lists drafts in the connected Gmail mailbox, up to max_results (default 50). Returns the drafts with ids.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"max_results":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.list-drafts","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.mark_read","description":"Marks each Gmail message in message_ids as read by removing its UNREAD label, one call per message; reports per-message success and failures.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_ids":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_ids"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.mark-read","http_method":"POST","dispatch_endpoint":null},{"name":"google.gmail.mark_unread","description":"Marks each Gmail message in message_ids as unread by adding the UNREAD label, one call per message; reports per-message success and failures.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_ids":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_ids"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.mark-unread","http_method":"POST","dispatch_endpoint":null},{"name":"google.gmail.reply","description":"Sends a reply on a Gmail thread (thread_id) from the connected mailbox, to the last sender or everyone with reply_all, and logs it in email_messages. Returns message_id and recipients.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"body":{"type":"string"},"reply_all":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","thread_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_gmail.reply","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.reply","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.search","description":"Searches the connected Gmail mailbox with Gmail query syntax (query), up to max_results. Returns message ids, thread ids, subject and To headers (no bodies) and a count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string"},"max_results":{"type":"integer"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.send","description":"Sends an email from the connected Gmail account (really sends) and records it in the email_messages table. Needs to, subject, body; cc, bcc, reply_to optional. Returns message_id and thread_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":"array"},"subject":{"type":"string"},"body":{"type":"string"},"cc":{"type":"array"},"bcc":{"type":"array"},"reply_to":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","subject","to"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_gmail.send","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"bcc_count":{},"cc":{},"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.send_draft","description":"Sends an existing draft (draft_id) from the connected Gmail mailbox. Returns the sent message_id, thread_id and labels.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"draft_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["draft_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.send-draft","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.send_template","description":"Sends an email through the connected Gmail account using one of this tenant's active email_templates rows (template_id), filling {{field}} merge_fields. Needs template_id and to.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"template_id":{"type":"string"},"to":{"type":"array"},"merge_fields":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["template_id","to"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.send-template","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.gmail.trash","description":"Moves each Gmail message in message_ids to Trash (recoverable for 30 days), one call per message; reports how many succeeded and which failed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_ids":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_ids"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/gmail.trash","http_method":"POST","dispatch_endpoint":null},{"name":"google.meet.create_meeting","description":"Creates an instant Google Meet (starting now) in the connected Google account, inviting any attendee emails. Needs summary. Returns the meeting with its Meet link and calendar event id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"summary":{"type":"string"},"attendees":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["summary"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/meet.create-meeting","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.meet.get_meeting","description":"Looks up a Google Meet meeting by its calendar event_id in the connected Google account. Returns the meeting details (link, times, attendees) or null.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"event_id":{"type":"string"}},"required":["event_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/meet.get-meeting","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.sheets.append_rows","description":"Appends rows (a list of row arrays) to the end of a sheet in a Google Sheets spreadsheet in the connected account. Needs spreadsheet_id, sheet_name, rows. Returns the updated range and count.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"sheet_name":{"type":"string"},"rows":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["rows","sheet_name","spreadsheet_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_sheets.append_rows","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/sheets.append-rows","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appended_rows":{},"range":{},"row_number":{},"spreadsheet_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.sheets.create_spreadsheet","description":"Create a new Google Spreadsheet, optionally seeded with a header row.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"headers":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/sheets.create-spreadsheet","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.sheets.get_values","description":"Reads every populated value on one tab of a Google Sheet (spreadsheet_id + sheet_name) and returns the rows as lists of formatted cell values.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"sheet_name":{"type":"string"}},"required":["sheet_name","spreadsheet_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/sheets.get-values","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.sheets.read_range","description":"Reads cell values from a Google Sheet (spreadsheet_id) for an A1 range_notation such as Sheet1!A1:D20; returns the rows, resolved range and major dimension.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"range_notation":{"type":"string"}},"required":["range_notation","spreadsheet_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/sheets.read-range","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.sheets.write_range","description":"Overwrites cells in an A1 range (range_notation) of a Google Sheets spreadsheet in the connected account with a 2D values array. Returns updated rows, columns and cells.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"range_notation":{"type":"string"},"values":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["range_notation","spreadsheet_id","values"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_sheets.write_range","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/sheets.write-range","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"range":{},"spreadsheet_id":{},"status":{},"updated_cells":{},"updated_columns":{},"updated_rows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.complete_task","description":"Marks a task complete in the connected Google Tasks account (not a CRM task). Needs task_list_id and task_id. Returns the updated Google task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"task_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id","task_list_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_tasks.complete","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.complete-task","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.create_task","description":"Creates a task in a Google Tasks list (task_list_id) of the connected Google account, not in the CRM. Needs title; notes and due (YYYY-MM-DD) optional. Returns the task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"title":{"type":"string"},"notes":{"type":"string"},"due":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_list_id","title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_tasks.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.create-task","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.create_task_list","description":"Creates a new task list in the connected Google Tasks account. Needs title. Returns the list with its id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.create-task-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.delete_task","description":"Delete a task in the connected Google account's Google Tasks (not the CRM task table); requires task_list_id and Google's string task_id. Returns ok and deleted, or ok false with the Google error.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"task_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id","task_list_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.delete-task","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deleted":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.list_tasks","description":"Lists tasks in a Google Tasks list (task_list_id) of the connected account; completed ones only when show_completed is true. Returns the tasks and a count. Not CRM tasks.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"show_completed":{"type":"boolean"}},"required":["task_list_id"]},"required_scope":null,"transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"google_not_connected","when":"The company has not connected Google.","override":null,"code_in_response":false},{"code":"google_needs_reauth","when":"The Google connection needs the owner to reconnect.","override":null,"code_in_response":false},{"code":"google_token_invalid","when":"Google rejected the token as expired or invalid.","override":null,"code_in_response":false}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.list-tasks","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.move_task","description":"Move a task (change parent or position).","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"task_id":{"type":"string"},"parent_id":{"type":"string"},"previous_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id","task_list_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.move-task","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google.tasks.update_task","description":"Updates a Google Tasks task (task_list_id, task_id) in the connected account: title, notes and due. The status argument is accepted but ignored. Returns the updated task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"task_id":{"type":"string"},"title":{"type":"string"},"notes":{"type":"string"},"due":{"type":"string"},"status":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id","task_list_id"]},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google/tasks.update-task","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_calendar.create_event","description":"Google Calendar — create an event on the primary calendar. Really creates it; named attendees receive a Google invite (outbound action).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"summary":{"type":"string"},"start_time":{"type":"string","description":"ISO-8601 with timezone."},"end_time":{"type":"string","description":"ISO-8601 with timezone."},"attendees":{"nullable":true,"type":"array","items":{"type":"string"}},"description":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"video_conference":{"type":"boolean","default":false},"title":{"nullable":true,"type":"string","description":"Same as summary."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["end_time","start_time"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_calendar/create-event","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"attendees_count":{},"end_time":{},"event_id":{},"html_link":{},"start_time":{},"status":{},"summary":{},"video_link":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_calendar_event_create","description":"Create an event on the user's primary Google Calendar. Times are ISO-8601 with timezone (e.g. 2026-06-01T15:00:00-06:00). Attendees receive a calendar invite from Google directly. Set with_meet_link=true to attach a Google Meet conferencing link. Returns a confirmation card — the event is NOT created until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Event title."},"start_time":{"type":"string","description":"ISO-8601 start (with tz)."},"end_time":{"type":"string","description":"ISO-8601 end (with tz)."},"description":{"type":"string","description":"Optional body / agenda."},"location":{"type":"string","description":"Optional location."},"attendees":{"type":"array","items":{"type":"string"},"description":"List of attendee emails (each gets a Google invite)."},"with_meet_link":{"type":"boolean","description":"Attach a Google Meet link. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","start_time","end_time"]},"required_scope":"integrations:write","transport":"dispatch","coordinate":"90","noun":"google","location":"svc.api","same_as":"google.calendar_event_create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"attendees_count":{},"end_time":{},"event_id":{},"hangout_link":{},"html_link":{},"preflight":{},"start_time":{},"status":{},"title":{},"with_meet_link":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_chat.create_space","description":"Google Chat — create a space. Really creates it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"display_name":{"type":"string"},"members":{"nullable":true,"type":"array","items":{"type":"string"}},"description":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["display_name"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_chat/create-space","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"display_name":{},"space_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_chat.send_message","description":"Google Chat — send a message to a space. Really sends.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"message":{"type":"string"},"thread_key":{"nullable":true,"type":"string"},"text":{"nullable":true,"type":"string","description":"Same as message."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["space_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_chat/send-message","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"space_id":{},"status":{},"thread_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_chat.send_notification","description":"Google Chat — send a notification card to a space. Really sends.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"space_id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"action_url":{"nullable":true,"type":"string"},"message":{"nullable":true,"type":"string","description":"Same as body."},"icon":{"nullable":true,"type":"string"},"thread_key":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["space_id","title"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_chat/send-notification","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"space_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_docs.create","description":"Google Docs — create a document, optionally with body text you supply. Really creates it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"nullable":true,"type":"string"},"folder_id":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_docs/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"document_id":{},"status":{},"title":{},"web_url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_docs.generate","description":"Google Docs — write a document from a brief and create it in the company's Google Drive. Spends AI credits; needs Google connected (checked before anything is generated).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":3},"title":{"nullable":true,"type":"string"},"folder_id":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prompt"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_docs/generate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"characters":{},"generated":{},"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_docs_read","description":"Read the text of a Google Doc the user points to (by document id or URL) from their connected Google account. Read-only. Returns the title and plain-text content. NOTE: with the current Google scope (drive.file) this reads docs Solid# created or that the user picked via the file picker; reading an arbitrary existing doc returns a scope error with the next step — never invent the contents.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document":{"type":"string","description":"Google Doc id or full docs.google.com URL."}},"required":["document"]},"required_scope":"comms:read","transport":"dispatch","coordinate":"90","noun":"google","location":"svc.api","same_as":"google.docs_read","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"char_count":{},"content":{},"document_id":{},"status":{},"title":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_gmail.create_draft","description":"Google Gmail — create a draft. Really creates it; nothing is sent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":["string","array"],"description":"One address or a list."},"subject":{"type":"string"},"body":{"type":"string"},"body_type":{"nullable":true,"type":"string","enum":["plain","html"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","subject","to"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_gmail/create-draft","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"draft_id":{},"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_gmail.reply","description":"Google Gmail — reply to an existing thread. Really sends.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"body":{"type":"string"},"reply_all":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","thread_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_gmail/reply","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_gmail.send","description":"Google Gmail — send a plain-text email FROM the company's connected Gmail. Really sends. For branded transactional mail use email.send instead.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":["string","array"],"description":"One address or a list."},"subject":{"type":"string"},"body":{"type":"string"},"cc":{"nullable":true,"type":["string","array"]},"bcc":{"nullable":true,"type":["string","array"]},"reply_to":{"nullable":true,"type":"string"},"body_type":{"nullable":true,"type":"string","enum":["plain","html"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","subject","to"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_gmail/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"bcc_count":{},"cc":{},"message_id":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_gmail_send","description":"Send a plain-text email from the user's connected Gmail account. Use when the user has linked Google and wants the email to come FROM their personal Gmail address. For transactional / branded company email use `email_send` instead (SendGrid/Postmark/Mailgun). Returns a confirmation card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to":{"type":"string","description":"Recipient email."},"subject":{"type":"string","description":"Subject line."},"body":{"type":"string","description":"Plain-text body."},"cc":{"type":"string","description":"Optional CC (single address)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to","subject","body"]},"required_scope":"integrations:write","transport":"dispatch","coordinate":"90","noun":"google","location":"svc.api","same_as":"google_gmail.send","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"body_chars":{},"cc":{},"message_id":{},"preflight":{},"status":{},"subject":{},"thread_id":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_meet.create_instant","description":"Google Meet — create an instant meeting and return its join link. Really creates it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"nullable":true,"type":"string"},"attendees":{"nullable":true,"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_meet/create-instant","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"calendar_event_id":{},"html_link":{},"join_url":{},"meeting_id":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_sheets.append_rows","description":"Google Sheets — append rows to a sheet. Really appends; `range` may be a sheet name or an A1 range (only the sheet name is used).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"range":{"type":"string"},"rows":{"type":"array","items":{"type":"array"}},"sheet_name":{"nullable":true,"type":"string","description":"Same as range."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["rows","spreadsheet_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_sheets/append-rows","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appended_rows":{},"range":{},"row_number":{},"spreadsheet_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_sheets.create","description":"Google Sheets — create a spreadsheet in the company's connected Google account. Really creates it; raises if Google is not connected.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"sheets":{"nullable":true,"type":"array","items":{"type":"string"},"description":"Optional sheet/tab names."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_sheets/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"spreadsheet_id":{},"spreadsheet_url":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_sheets.sync_to_db","description":"Google Sheets — upsert this company's rows in one table from a sheet. Row 1 is the header and names the columns; key_column matches existing rows. Allowed tables only (e.g. contacts, products); everything is scoped to this company. Really writes.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"sheet_name":{"type":"string"},"table_name":{"type":"string","description":"one of the sync allowlist, e.g. contacts or products"},"key_column":{"type":"string","description":"column that identifies a row, e.g. email or sku"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["key_column","sheet_name","spreadsheet_id","table_name"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_sheets/sync-to-db","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"inserted":{},"status":{},"synced_rows":{},"table":{},"updated":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_sheets.write_range","description":"Google Sheets — write values to an A1 range. Really writes; returns updated cell counts.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"spreadsheet_id":{"type":"string"},"range":{"type":"string"},"values":{"type":"array","items":{"type":"array"}},"range_notation":{"nullable":true,"type":"string","description":"Same as range."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["spreadsheet_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_sheets/write-range","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"range":{},"spreadsheet_id":{},"status":{},"updated_cells":{},"updated_columns":{},"updated_rows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_tasks.complete","description":"Google Tasks — mark a task completed. Really updates it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"task_list_id":{"type":"string"},"task_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task_id","task_list_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_tasks/complete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"completed_at":{},"status":{},"task_id":{},"task_list_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"google_tasks.create","description":"Google Tasks — create a task. Really creates it (defaults to the @default list).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"task_list_id":{"nullable":true,"type":"string"},"notes":{"nullable":true,"type":"string"},"due":{"nullable":true,"type":"string","format":"date","description":"Due date, YYYY-MM-DD."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"90","noun":"google","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/google_tasks/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"task_id":{},"task_list_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"grounding.gaps","description":"Report what durable business context is still MISSING for this company — the 'what should I ask?' oracle. Returns a prioritized list of gaps (unique selling proposition, target audience, service area, service list, KB coverage) each with the exact question to ask the owner and the write verb to persist the answer. Call before writing pages/copy, or whenever get_brand_truth is unconfigured, so you run a precise intake instead of a vague 'tell me about your business'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"89","noun":"grounding","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/grounding/gaps","http_method":"POST","dispatch_endpoint":null},{"name":"grounding_gaps","description":"Report what durable business context is still MISSING for this company — the 'what should I ask?' oracle. Returns a prioritized list of gaps (unique selling proposition, target audience, service area, service list, KB coverage) each with the exact question to ask the owner and the write verb to persist the answer. Call before writing pages/copy, or whenever get_brand_truth is unconfigured, so you run a precise intake instead of a vague 'tell me about your business'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"89","noun":"grounding","location":"svc.api","same_as":"grounding.gaps","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"intent":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"gtm.activate_strategy","description":"GTM — activate a strategy (deactivates the company's others). Really persists it; the strategy is resolved company-scoped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"strategy_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["strategy_id"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"96","noun":"gtm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gtm/activate-strategy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"current_layer":{},"name":{},"status":{},"strategy_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"gtm.ai_suggest","description":"GTM — AI suggestions. NOT implemented; ALWAYS RAISES. POST /api/v1/gtm/ai/suggest is itself a declared stub returning placeholder prose.","shape":"suggest","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"context":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["context"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"96","noun":"gtm","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gtm/ai-suggest","http_method":"POST","dispatch_endpoint":null},{"name":"gtm.create_strategy","description":"GTM — create a go-to-market strategy and make it the active one. Really persists it. gtm_strategies has no target_market/description column, so those inputs are stored under layer_data.intake rather than dropped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"target_market":{"nullable":true,"type":"string"},"description":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"96","noun":"gtm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/gtm/create-strategy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"current_layer":{},"intake_stored_at":{},"is_active":{},"name":{},"status":{},"strategy_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.appointment_book","description":"Book a telehealth appointment with a licensed clinician. Visit types: intake, follow_up, med_review, behavioral, nutrition. Times are ISO 8601. cash_or_insurance controls how the encounter gets billed (Spectrum Care does NOT do subscriptions).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"clinician_id":{"type":"integer"},"scheduled_time":{"type":"string","description":"ISO 8601 start time."},"duration_minutes":{"type":"integer","minimum":10,"maximum":240},"visit_type":{"type":"string","enum":["intake","follow_up","med_review","behavioral","nutrition"]},"cash_or_insurance":{"type":"string","enum":["cash","insurance"]},"reason":{"type":"string","maxLength":1000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","scheduled_time","duration_minutes"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/appointment-book","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.cases.create","description":"Create a new patient case (company_id required for tenant isolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["data"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.create_case","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/cases.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.cases.get","description":"Get case details (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"case_id":{"type":"integer"}},"required":["case_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/cases.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.cases.list","description":"List cases with filters (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"status":{"type":"string"},"skip":{"type":"integer"},"limit":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/cases.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.claim_submit","description":"Submit a claim to a payer. UCP TYPED-PHRASE GATED — claim submission sends money outward + PHI to a third party. The typed phrase includes the amount so a wrong-amount slip is caught before submit. Phase 5 actually transmits to the clearinghouse (Availity / Change Healthcare / Stedi); today the claim state machine advances.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"claim_id":{"type":"integer"},"claim_number":{"type":"string"},"billed_amount":{"type":"number","minimum":0.01},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["claim_id","claim_number","billed_amount"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/claim-submit","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.create_case","description":"Healthcare — open a clinical case for a patient. chief_complaint is required (NOT NULL). The patient is resolved under company_id first, so a case cannot be attached to another tenant's patient.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer","minimum":1},"case_type":{"type":"string","description":"injury, illness, wellness, preventive"},"chief_complaint":{"type":"string"},"description":{"nullable":true,"type":"string","description":"Stored as the clinical impression."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","case_type","chief_complaint"],"additionalProperties":true},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/create-case","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"case_id":{},"company_id":{},"id":{},"patient_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.create_patient","description":"Healthcare — create a patient record (PHI, encrypted at rest). date_of_birth is required: the column is NOT NULL and a chart without one cannot be safely matched to a person.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"First and last name; both are required."},"date_of_birth":{"type":"string","description":"ISO date, YYYY-MM-DD."},"email":{"nullable":true,"type":"string"},"phone":{"nullable":true,"type":"string"},"sex":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","date_of_birth"],"additionalProperties":true},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"name_needs_first_and_last","when":"The name is a single word; a first and last name are required.","override":null,"code_in_response":false}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/create-patient","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"id":{},"patient_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.create_soap_note","description":"Healthcare — write an UNSIGNED draft SOAP note into a chart. Never signs (a signature is a clinician attesting to their own findings). case_id and provider_id are required and are both verified to belong to this company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer","minimum":1},"case_id":{"type":"integer","minimum":1},"provider_id":{"type":"integer","minimum":1},"subjective":{"type":"string"},"objective":{"type":"string"},"assessment":{"type":"string"},"plan":{"type":"string"},"date_of_service":{"nullable":true,"type":"string","description":"ISO date; defaults to today."},"note_type":{"type":"string","default":"progress","enum":["initial","progress","discharge","re_eval"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","case_id","provider_id","subjective","objective","assessment","plan"],"additionalProperties":true},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/create-soap-note","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"case_id":{},"date_of_service":{},"id":{},"is_signed":{},"note":{},"note_id":{},"patient_id":{},"provider_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.dexter.create_conversation","description":"Create a new Dexter conversation (company_id required for tenant isolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider_id":{"type":"integer"},"initial_message":{"type":"string"},"patient_id":{"type":"integer"},"case_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["initial_message","provider_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/dexter.create-conversation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.dexter.get_conversation","description":"Get a specific Dexter conversation (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"conversation_id":{"type":"string"}},"required":["conversation_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/dexter.get-conversation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.dexter.list_conversations","description":"List Dexter conversations (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider_id":{"type":"integer"},"patient_id":{"type":"integer"},"skip":{"type":"integer"},"limit":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/dexter.list-conversations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.dexter.send_message","description":"Send a message to Dexter (company_id required for tenant isolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"conversation_id":{"type":"string"},"content":{"type":"string"},"voice_input":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","conversation_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/dexter.send-message","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.eligibility_check","description":"Return active eligibility records for a patient. Used by the billing surface before booking to display patient responsibility. Spectrum Care does NOT do subscriptions — every visit is insurance OR cash pay.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"}},"required":["patient_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/eligibility-check","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.escalate_urgent","description":"SAFETY ESCAPE VALVE for the parent assistant when a safety keyword (self-harm, suicide, seizure, overdose, etc.) is detected. Always called regardless of confirmation. STUB (2026-09-07): it RECORDS the concern in the audit log and returns delivered=false — there is NO paging channel yet, so it CANNOT reach a clinician or the care team. On its result the assistant must tell the caller to call 911 / local emergency services now, and must NOT say the care team will reach out.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"concern":{"type":"string","minLength":1,"maxLength":2000},"matched_keywords":{"type":"array","items":{"type":"string"},"description":"The safety keywords that triggered escalation."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","concern"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"degraded","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/escalate-urgent","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.intake_submit","description":"Submit a completed intake form for scoring. The parent app + AI assistant call this when the parent finishes a screener. Severity band is computed from the published algorithm — unknown algorithms fail-safe to 'score_inconclusive'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer"},"patient_id":{"type":"integer"},"answers":{"type":"array","items":{"type":"object"},"description":"Array of {question_id, answer_value}."},"total_score":{"type":"number"},"max_score":{"type":"number","minimum":0.01},"scoring_algorithm":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id","patient_id","answers"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/intake-submit","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.lab_order_send","description":"Send a lab order to a partner lab. UCP TYPED-PHRASE GATED — lab orders carry PHI to a third party. Phase 5 actually transmits via HL7/FHIR; today the order state machine advances and the typed-phrase signature is recorded for audit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"patient_id":{"type":"integer"},"test_code":{"type":"string","description":"LOINC test code (e.g. 2160-0)."},"test_name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","patient_id","test_code","test_name"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/lab-order-send","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.lab_result_release","description":"Release a lab result to the parent app. Clinician sign-off + interpretation note attached. Parents NEVER see results before the clinician releases them — this verb is the gate.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"result_id":{"type":"integer"},"interpretation_note":{"type":"string","maxLength":4000,"description":"Parent-facing context — e.g. 'this is within normal range for your child's age'. NEVER diagnostic."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["result_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/lab-result-release","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.message_send","description":"Send a secure message into a patient's care thread. Use this from the parent assistant when the parent has a question for the care team OR from the clinician side when responding.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"body":{"type":"string","minLength":1,"maxLength":4000},"priority":{"type":"string","enum":["routine","urgent"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","body"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/message-send","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.milestone_log","description":"Log a developmental milestone observation for a patient. Categories: motor, cognitive, social, language, sensory, self_care, emotional. NEVER diagnostic — status defaults to 'observed'. Only a clinician can move to 'reviewed_by_clinician'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"category":{"type":"string","enum":["motor","cognitive","social","language","sensory","self_care","emotional"]},"milestone_name":{"type":"string","minLength":1,"maxLength":255},"tracking_scale":{"type":"string"},"achieved_date":{"type":"string","format":"date"},"note":{"type":"string","maxLength":4000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","category","milestone_name"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/milestone-log","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.milestone_recent","description":"Return recent developmental milestone observations for a patient. Used by the clinician summary view and the parent dashboard. Observational ONLY — milestones are never diagnostic; severity bands are research thresholds.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"limit":{"type":"integer","minimum":1,"maximum":100}},"required":["patient_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/milestone-recent","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.patient_list","description":"List patients (children) under this tenant's care. Returns demographics + status. Use this when the parent app needs the family overview OR when a clinician opens their patient panel.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"search":{"type":"string","description":"Optional fuzzy match on name, ID, email.","maxLength":120},"limit":{"type":"integer","description":"Page size 1-200. Default 100.","minimum":1,"maximum":200}}},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/patient-list","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.patients.create","description":"Create a new patient record (HIPAA-compliant, company_id required for tenantisolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["data"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.create_patient","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/patients.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.patients.get","description":"Get patient details (HIPAA access logging, company_id required for tenantisolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"}},"required":["patient_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/patients.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.patients.list","description":"List patients with search and pagination (company_id required for tenantisolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"search":{"type":"string"},"skip":{"type":"integer"},"limit":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/patients.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.patients.update","description":"Update patient information (company_id required for tenant isolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["data","patient_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/patients.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.prescription_draft","description":"Draft a prescription. Creates the Rx in status 'draft' — does NOT send to the pharmacy. Sending requires healthcare_prescription_send which is UCP typed-phrase gated.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"drug_name":{"type":"string","minLength":1,"maxLength":255},"dose":{"type":"string","maxLength":100},"sig":{"type":"string","maxLength":2000},"refills_allowed":{"type":"integer","minimum":0,"maximum":12},"dea_schedule":{"type":"string","enum":["II","III","IV","V"],"description":"DEA controlled-substance schedule. Omit for non-controlled."},"ndc_code":{"type":"string","maxLength":20},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","drug_name"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/prescription-draft","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.prescription_send","description":"Send a prescription to the pharmacy. UCP TYPED-PHRASE GATED — the clinician must type the exact phrase the dispatcher echoes. Controlled substances include the DEA schedule in the phrase. Phase 5 actually transmits via Surescripts or DEA-compliant fax; today the prescription state machine advances and the typed-phrase signature is recorded for audit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prescription_id":{"type":"integer"},"patient_id":{"type":"integer"},"drug_name":{"type":"string"},"dea_schedule":{"type":"string","enum":["II","III","IV","V"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prescription_id","patient_id","drug_name"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/prescription-send","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.soap_draft","description":"Draft a SOAP note for a clinical encounter. Status stays 'draft' until the clinician calls healthcare_soap_sign. AI agents (clinical_summarizer) call this to seed the note from the telehealth transcript; the clinician reviews + signs.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"case_id":{"type":"integer"},"subjective":{"type":"string","maxLength":8000},"objective":{"type":"string","maxLength":8000},"assessment":{"type":"string","maxLength":8000},"plan":{"type":"string","maxLength":8000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","case_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-draft","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare.soap_notes.create","description":"Create a new SOAP note (company_id required for tenant isolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["data"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.create_soap_note","status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-notes.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.soap_notes.get","description":"Get SOAP note details (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_id":{"type":"integer"}},"required":["note_id"]},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-notes.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.soap_notes.list","description":"List SOAP notes (company_id required for tenant isolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"case_id":{"type":"integer"},"skip":{"type":"integer"},"limit":{"type":"integer"}}},"required_scope":null,"transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-notes.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.soap_notes.sign","description":"Digitally sign a SOAP note (company_id required for tenant isolation).","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_id":{"type":"integer"},"signature_data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["note_id","signature_data"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-notes.sign","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare.soap_sign","description":"Sign a SOAP note. Locks the note for further edits and stamps the signing clinician + timestamp. Clinician-only — AI agents draft but NEVER sign autonomously.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"soap_note_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["soap_note_id"]},"required_scope":"healthcare:write","transport":"http","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/healthcare/soap-sign","http_method":"POST","dispatch_endpoint":null},{"name":"healthcare_appointment_book","description":"Book a telehealth appointment with a licensed clinician. Visit types: intake, follow_up, med_review, behavioral, nutrition. Times are ISO 8601. cash_or_insurance controls how the encounter gets billed (Spectrum Care does NOT do subscriptions).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"clinician_id":{"type":"integer"},"scheduled_time":{"type":"string","description":"ISO 8601 start time."},"duration_minutes":{"type":"integer","minimum":10,"maximum":240},"visit_type":{"type":"string","enum":["intake","follow_up","med_review","behavioral","nutrition"]},"cash_or_insurance":{"type":"string","enum":["cash","insurance"]},"reason":{"type":"string","maxLength":1000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","scheduled_time","duration_minutes"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.appointment_book","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"appointment_id":{},"cash_or_insurance":{},"patient_id":{},"scheduled_time":{},"status":{},"visit_type":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_claim_submit","description":"Submit a claim to a payer. UCP TYPED-PHRASE GATED — claim submission sends money outward + PHI to a third party. The typed phrase includes the amount so a wrong-amount slip is caught before submit. Phase 5 actually transmits to the clearinghouse (Availity / Change Healthcare / Stedi); today the claim state machine advances.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"claim_id":{"type":"integer"},"claim_number":{"type":"string"},"billed_amount":{"type":"number","minimum":0.01},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["claim_id","claim_number","billed_amount"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.claim_submit","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"claim":{},"phase":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_eligibility_check","description":"Return active eligibility records for a patient. Used by the billing surface before booking to display patient responsibility. Spectrum Care does NOT do subscriptions — every visit is insurance OR cash pay.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"}},"required":["patient_id"]},"required_scope":null,"transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.eligibility_check","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"eligibility":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_escalate_urgent","description":"SAFETY ESCAPE VALVE for the parent assistant when a safety keyword (self-harm, suicide, seizure, overdose, etc.) is detected. Always called regardless of confirmation. STUB (2026-09-07): it RECORDS the concern in the audit log and returns delivered=false — there is NO paging channel yet, so it CANNOT reach a clinician or the care team. On its result the assistant must tell the caller to call 911 / local emergency services now, and must NOT say the care team will reach out.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"concern":{"type":"string","minLength":1,"maxLength":2000},"matched_keywords":{"type":"array","items":{"type":"string"},"description":"The safety keywords that triggered escalation."}},"required":["patient_id","concern"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.escalate_urgent","status":"degraded","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"assistant_instruction":{},"delivered":{},"matched_keywords":{},"patient_id":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_intake_submit","description":"Submit a completed intake form for scoring. The parent app + AI assistant call this when the parent finishes a screener. Severity band is computed from the published algorithm — unknown algorithms fail-safe to 'score_inconclusive'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"form_id":{"type":"integer"},"patient_id":{"type":"integer"},"answers":{"type":"array","items":{"type":"object"},"description":"Array of {question_id, answer_value}."},"total_score":{"type":"number"},"max_score":{"type":"number","minimum":0.01},"scoring_algorithm":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["form_id","patient_id","answers"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.intake_submit","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"assessment_score_id":{},"phase_note":{},"severity_band":{},"status":{},"total_score":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_lab_order_send","description":"Send a lab order to a partner lab. UCP TYPED-PHRASE GATED — lab orders carry PHI to a third party. Phase 5 actually transmits via HL7/FHIR; today the order state machine advances and the typed-phrase signature is recorded for audit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"patient_id":{"type":"integer"},"test_code":{"type":"string","description":"LOINC test code (e.g. 2160-0)."},"test_name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","patient_id","test_code","test_name"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.lab_order_send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"order":{},"phase":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_lab_result_release","description":"Release a lab result to the parent app. Clinician sign-off + interpretation note attached. Parents NEVER see results before the clinician releases them — this verb is the gate.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"result_id":{"type":"integer"},"interpretation_note":{"type":"string","maxLength":4000,"description":"Parent-facing context — e.g. 'this is within normal range for your child's age'. NEVER diagnostic."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["result_id"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.lab_result_release","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"result":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_message_send","description":"Send a secure message into a patient's care thread. Use this from the parent assistant when the parent has a question for the care team OR from the clinician side when responding.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"body":{"type":"string","minLength":1,"maxLength":4000},"priority":{"type":"string","enum":["routine","urgent"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","body"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.message_send","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"patient_id":{},"phase":{},"priority":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_milestone_log","description":"Log a developmental milestone observation for a patient. Categories: motor, cognitive, social, language, sensory, self_care, emotional. NEVER diagnostic — status defaults to 'observed'. Only a clinician can move to 'reviewed_by_clinician'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"category":{"type":"string","enum":["motor","cognitive","social","language","sensory","self_care","emotional"]},"milestone_name":{"type":"string","minLength":1,"maxLength":255},"tracking_scale":{"type":"string"},"achieved_date":{"type":"string","format":"date"},"note":{"type":"string","maxLength":4000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","category","milestone_name"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.milestone_log","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"milestone":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_milestone_recent","description":"Return recent developmental milestone observations for a patient. Used by the clinician summary view and the parent dashboard. Observational ONLY — milestones are never diagnostic; severity bands are research thresholds.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"limit":{"type":"integer","minimum":1,"maximum":100}},"required":["patient_id"]},"required_scope":null,"transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.milestone_recent","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"milestones":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_patient_list","description":"List patients (children) under this tenant's care. Returns demographics + status. Use this when the parent app needs the family overview OR when a clinician opens their patient panel.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"search":{"type":"string","description":"Optional fuzzy match on name, ID, email.","maxLength":120},"limit":{"type":"integer","description":"Page size 1-200. Default 100.","minimum":1,"maximum":200}}},"required_scope":null,"transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.patient_list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"patients":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_prescription_draft","description":"Draft a prescription. Creates the Rx in status 'draft' — does NOT send to the pharmacy. Sending requires healthcare_prescription_send which is UCP typed-phrase gated.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"drug_name":{"type":"string","minLength":1,"maxLength":255},"dose":{"type":"string","maxLength":100},"sig":{"type":"string","maxLength":2000},"refills_allowed":{"type":"integer","minimum":0,"maximum":12},"dea_schedule":{"type":"string","enum":["II","III","IV","V"],"description":"DEA controlled-substance schedule. Omit for non-controlled."},"ndc_code":{"type":"string","maxLength":20},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","drug_name"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.prescription_draft","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"prescription":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_prescription_send","description":"Send a prescription to the pharmacy. UCP TYPED-PHRASE GATED — the clinician must type the exact phrase the dispatcher echoes. Controlled substances include the DEA schedule in the phrase. Phase 5 actually transmits via Surescripts or DEA-compliant fax; today the prescription state machine advances and the typed-phrase signature is recorded for audit.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prescription_id":{"type":"integer"},"patient_id":{"type":"integer"},"drug_name":{"type":"string"},"dea_schedule":{"type":"string","enum":["II","III","IV","V"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prescription_id","patient_id","drug_name"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.prescription_send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"phase":{},"prescription":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_soap_draft","description":"Draft a SOAP note for a clinical encounter. Status stays 'draft' until the clinician calls healthcare_soap_sign. AI agents (clinical_summarizer) call this to seed the note from the telehealth transcript; the clinician reviews + signs.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"patient_id":{"type":"integer"},"case_id":{"type":"integer"},"subjective":{"type":"string","maxLength":8000},"objective":{"type":"string","maxLength":8000},"assessment":{"type":"string","maxLength":8000},"plan":{"type":"string","maxLength":8000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["patient_id","case_id"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.soap_draft","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"soap_note_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"healthcare_soap_sign","description":"Sign a SOAP note. Locks the note for further edits and stamps the signing clinician + timestamp. Clinician-only — AI agents draft but NEVER sign autonomously.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"soap_note_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["soap_note_id"]},"required_scope":"healthcare:write","transport":"dispatch","coordinate":"38","noun":"healthcare","location":"svc.api","same_as":"healthcare.soap_sign","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"patient_id":{},"soap_note_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"history.entity","description":"List version history for any business entity (contact, product, deal, service, order, appointment).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"entity_type":{"type":"string","minLength":1},"entity_id":{"type":"integer","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"required":["entity_type"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"history","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/history/entity","http_method":"POST","dispatch_endpoint":null},{"name":"history.recent","description":"List all recent entity changes across the company — contacts, products, deals, orders, everything.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"history","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/history/recent","http_method":"POST","dispatch_endpoint":null},{"name":"history.rollback","description":"Rollback any business entity to a previous version. Restores the state_before from the target version.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"entity_type":{"type":"string","minLength":1},"entity_id":{"type":"integer","minimum":1},"version":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["entity_id","entity_type","version"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"history","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/history/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"inbox.archive","description":"Archive an inbox thread to clear it off the list: marked read and archived — found again under Archived, never deleted. The same action as swiping a thread on the phone. undo=true puts it back. thread_id is an inbox row id from inbox.list (e.g. 'email_12456', 'voice_12', 'chat_<uuid>'); works on every channel — an email's whole thread, or the call, text, chat or form thread.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"undo":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["thread_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"660","noun":"inbox_thread","acts_on":{"noun":"inbox_thread","address":"660","domain":"Inbox","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inbox/archive","http_method":"POST","dispatch_endpoint":null},{"name":"inbox.explain","description":"Why an inbox thread is in People, Sales or Spam: the sender verdict (client/lead/vendor/third_party/personal/team/sales/automated/spam), who decided it (user = the owner moved it, provider = Gmail/SendGrid's own verdict, rule, shape = the email is built like bulk mail, ai), the reason, and the email's shape signals read now (mailing-list headers, sending subdomain, unsubscribe footer, tracking links, newsletter layout, or person signals such as a reply in a thread). thread_id from inbox.list. Read-only. Pair with inbox.move to change it.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"}},"required":["thread_id"],"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"660","noun":"inbox_thread","acts_on":{"noun":"inbox_thread","address":"660","domain":"Inbox","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inbox/explain","http_method":"POST","dispatch_endpoint":null},{"name":"inbox.list","description":"The owner's unified inbox — calls, email, web chat, texts and forms in one list, newest first. view=people (clients, leads, people they know; the default) | sales (newsletters, marketing, vendor pitches, automated mail) | spam. lane=calls|email|chat|text|form narrows it by how it came in. Each row says who it is from (sender: client/lead/vendor/third_party/personal/team/sales/automated/spam), how it came in (lane, via e.g. 'Gmail · owner@', 'System email · hello@', 'Website chat', 'Website voice chat', 'Phone call'), what KIND of conversation it was (kind: phone_call = a real phone line; website_voice = a visitor spoke with the AI through their browser on the website — never call it a phone call; website_chat = the typed website chat; in_app = the team's own session) and a preview; counts gives total and unread per view. folder=saved lists the threads the owner cleared with SAVE (what they handled), folder=archived the ones they cleared with ARCHIVE (recoverable — nothing is destroyed). Every row carries the universal reader's one answer for its message: sender (who they are to the business: client/lead/vendor/third_party/personal/team/sales/automated/spam), acting_for (whom a third party speaks for), ask (what they want, one line) and needs_reply. needs_reply=true lists only what waits on the owner, across every channel.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"view":{"type":"string","enum":["people","sales","spam"]},"lane":{"type":"string","enum":["calls","email","text","chat","form"]},"folder":{"type":"string","enum":["inbox","saved","archived"]},"search":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0},"needs_reply":{"type":"boolean"}},"additionalProperties":true},"required_scope":"comms:read","transport":"http","coordinate":"660","noun":"inbox_thread","acts_on":{"noun":"inbox_thread","address":"660","domain":"Inbox","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inbox/list","http_method":"POST","dispatch_endpoint":null},{"name":"inbox.move","description":"Move an email's sender to People, Sales or Spam (to=people|sales|spam, or customer (=client)|lead|contact (=personal)|vendor|third_party|personal|automated — these file the sender as a person: a lead gets a deal at New when they have none open, a vendor is linked to an AP vendor; vendor = someone the business pays; third_party = someone acting for another company — a lawyer, a collections agent). Every email from that address moves, and the sorter uses the owner's decision first for their next one — the same move the Inbox screen makes on the web and the phone. thread_id is an inbox row id from inbox.list, e.g. 'email_12456', 'sms_40', 'voice_12'. Works on every channel: an email sender moves by address; a caller or texter by phone number; a chat or form by the email or phone they left (an anonymous web visitor returns no_sender).","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"to":{"type":"string","enum":["people","sales","spam","client","customer","lead","contact","vendor","third_party","personal","automated"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["thread_id","to"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"660","noun":"inbox_thread","acts_on":{"noun":"inbox_thread","address":"660","domain":"Inbox","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inbox/move","http_method":"POST","dispatch_endpoint":null},{"name":"inbox.save","description":"Save an inbox thread to clear it off the list: marked read, starred and archived — kept, found again under Starred. The same action as swiping a thread on the phone. undo=true puts it back. thread_id is an inbox row id from inbox.list (e.g. 'email_12456', 'voice_12', 'chat_<uuid>'); works on every channel — an email's whole thread, or the call, text, chat or form thread.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"undo":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["thread_id"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"660","noun":"inbox_thread","acts_on":{"noun":"inbox_thread","address":"660","domain":"Inbox","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inbox/save","http_method":"POST","dispatch_endpoint":null},{"name":"infrastructure.diagnose","description":"Diagnose the tenant's managed droplet — overall health, CPU / memory / disk usage, per-service status (backend, frontend, database, redis, mcp), and Celery queue depth. Read-only; safe to call freely. Use this BEFORE proposing a resize so the recommendation has data behind it.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/infrastructure/diagnose","http_method":"POST","dispatch_endpoint":null},{"name":"infrastructure.preview_resize","description":"Project the cost delta and reversibility of resizing the droplet to a target size, WITHOUT calling the DigitalOcean API. Use this before infrastructure_resize so the owner sees the price change before typing the confirmation phrase. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_size_slug":{"type":"string","enum":["SMALL","MEDIUM","LARGE","GPU"],"description":"Target droplet size (SMALL, MEDIUM, LARGE, GPU)."}},"required":["target_size_slug"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/infrastructure/preview-resize","http_method":"POST","dispatch_endpoint":null},{"name":"infrastructure.resize","description":"Resize the tenant's managed droplet to a target size via DigitalOcean CPU-only resize. Brief downtime during swap. Reversible — call again with the original size. Owner role + typed phrase required. Always call infrastructure_preview_resize first so the owner sees the price delta.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_size_slug":{"type":"string","enum":["SMALL","MEDIUM","LARGE","GPU"],"description":"Target droplet size (SMALL, MEDIUM, LARGE, GPU)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_size_slug"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/infrastructure/resize","http_method":"POST","dispatch_endpoint":null},{"name":"infrastructure.scale_workers","description":"Adjust Celery worker count on the tenant's managed droplet. Positive delta adds workers, negative removes. Floor: 1 worker. Ceiling: droplet vCPU count × 4. Scale-down can drop in-flight tasks — owner role + typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"delta_workers":{"type":"integer","description":"Number of workers to add (positive) or remove (negative). Must be non-zero."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["delta_workers"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/infrastructure/scale-workers","http_method":"POST","dispatch_endpoint":null},{"name":"infrastructure_diagnose","description":"Diagnose the tenant's managed droplet — overall health, CPU / memory / disk usage, per-service status (backend, frontend, database, redis, mcp), and Celery queue depth. Read-only; safe to call freely. Use this BEFORE proposing a resize so the recommendation has data behind it.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":"infrastructure.diagnose","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"droplet_id":{},"health":{},"ip":{},"overall":{},"queue_depth":{},"recommendation":{},"region":{},"resources":{},"size":{},"size_slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"infrastructure_preview_resize","description":"Project the cost delta and reversibility of resizing the droplet to a target size, WITHOUT calling the DigitalOcean API. Use this before infrastructure_resize so the owner sees the price change before typing the confirmation phrase. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_size_slug":{"type":"string","enum":["SMALL","MEDIUM","LARGE","GPU"],"description":"Target droplet size (SMALL, MEDIUM, LARGE, GPU)."}},"required":["target_size_slug"]},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":"infrastructure.preview_resize","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_price_monthly_cents":{},"current_size":{},"current_size_slug":{},"delta_cents":{},"notes":{},"preflight":{},"reversible":{},"target_price_monthly_cents":{},"target_size":{},"target_size_slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"infrastructure_resize","description":"Resize the tenant's managed droplet to a target size via DigitalOcean CPU-only resize. Brief downtime during swap. Reversible — call again with the original size. Owner role + typed phrase required. Always call infrastructure_preview_resize first so the owner sees the price delta.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_size_slug":{"type":"string","enum":["SMALL","MEDIUM","LARGE","GPU"],"description":"Target droplet size (SMALL, MEDIUM, LARGE, GPU)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_size_slug"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":"infrastructure.resize","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_size":{},"delta_cents":{},"new_price_monthly_cents":{},"new_size":{},"new_size_slug":{},"preflight":{},"previous_size":{},"previous_size_slug":{},"rollback_handle":{},"status":{},"stub_mode":{},"target_size":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"infrastructure_scale_workers","description":"Adjust Celery worker count on the tenant's managed droplet. Positive delta adds workers, negative removes. Floor: 1 worker. Ceiling: droplet vCPU count × 4. Scale-down can drop in-flight tasks — owner role + typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"delta_workers":{"type":"integer","description":"Number of workers to add (positive) or remove (negative). Must be non-zero."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["delta_workers"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"infrastructure","location":"svc.api","same_as":"infrastructure.scale_workers","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ceiling":{},"current_workers":{},"delta":{},"delta_workers":{},"new_workers":{},"preflight":{},"previous_workers":{},"rollback_handle":{},"status":{},"stub_mode":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"insights.call_evaluation_summary","description":"Communications evaluation rollup over a window (default 7 days). Calls: scored count, avg 0-100 quality, grade mix, resolution + escalation rates, outcomes, lowest-scoring calls to review first. Message channels (sms/email/chat): response coverage, negative rate, anger band, and the needs-reply queue (unanswered negatives). Optionally filtered to one phone line.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":7},"phone_number":{"type":"string","nullable":true,"pattern":"^\\+?[0-9]{7,15}$"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"16","noun":"insights","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/insights/call-evaluation-summary","http_method":"POST","dispatch_endpoint":null},{"name":"insights.master_summary","description":"The master communications report in one call — everything the Insights Overview shows: cross-channel sentiment (voice/sms/email/chat + combined), call evaluation + message-channel handling (response coverage, needs-reply queue), per-day volume trend, and the needs-attention feed. The best single answer to 'how are my customer communications doing?'.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":7}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"16","noun":"insights","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/insights/master-summary","http_method":"POST","dispatch_endpoint":null},{"name":"insights.sentiment_summary","description":"Cross-channel customer sentiment rollup over a window (default 7 days): voice + SMS + email + chat mood mixes, a combined all-communications view, per-line breakdown, AI-vs-human answered, and the negative calls that need attention. Optionally filtered to one phone line.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":7},"phone_number":{"type":"string","nullable":true,"pattern":"^\\+?[0-9]{7,15}$"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"16","noun":"insights","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/insights/sentiment-summary","http_method":"POST","dispatch_endpoint":null},{"name":"integration.accounting_connect","description":"Initiate OAuth connection for an accounting system (QuickBooks, Xero, FreshBooks). Returns an OAuth URL. Universal — works for any provider in the accounting registry.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider":{"type":"string","minLength":1},"redirect_uri":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["provider"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-connect","http_method":"POST","dispatch_endpoint":null},{"name":"integration.accounting_disconnect","description":"Disconnect an accounting system. Revokes OAuth token.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"connection_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["connection_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-disconnect","http_method":"POST","dispatch_endpoint":null},{"name":"integration.accounting_expense_setup","description":"Where money OUT lands in the connected accounting system (QuickBooks, Xero, FreshBooks): whether expense sync is on, the chosen expense and payment accounts, what is still missing, how many purchases are synced / pending / failed, and (include_accounts) the accounts in their books to choose from. Change it with the accounting_expense_settings action; send with expense_sync.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_accounts":{"type":"boolean","default":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-expense-setup","http_method":"POST","dispatch_endpoint":null},{"name":"integration.accounting_list","description":"List all connected accounting systems for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connections":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.accounting_receivable_setup","description":"Where money IN lands in the connected accounting system (QuickBooks, Xero, FreshBooks): whether invoices are being sent and from which date, the chosen sales item / account, tax and deposit accounts, what is still missing, how many invoices are synced / failed / excluded, and (include_accounts) what can be chosen in their books. Change it with accounting_receivable_settings; send with invoice_sync.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_accounts":{"type":"boolean","default":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-receivable-setup","http_method":"POST","dispatch_endpoint":null},{"name":"integration.accounting_sync","description":"Trigger a manual sync with a connected accounting system.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"connection_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["connection_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-sync","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connection_id":{},"provider":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.accounting_sync_status","description":"Check the sync status and recent sync history for an accounting connection.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"connection_id":{"type":"integer","minimum":1}},"required":["connection_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"502","noun":"accounting_connection","acts_on":{"noun":"accounting_connection","address":"502","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/accounting-sync-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connection_id":{},"last_sync_at":{},"provider":{},"recent_logs":{},"status":{},"sync_enabled":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.connect_api_key","description":"Connect a payment processor via API key (Authorize.net, Adyen, Worldpay, NMI, Shift4, etc.). Universal — works for any API-key processor.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"processor":{"type":"string","minLength":1},"credentials":{"type":"object"},"environment":{"type":"string","default":"production"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["credentials","processor"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/connect-api-key","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"is_default":{},"merchant_account_id":{},"processor":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.connect_oauth","description":"Initiate OAuth connection for a payment processor (Stripe, Square, PayPal, Toast, Clover, Braintree, etc.). Returns an OAuth URL for the user to visit. Universal — works for any OAuth-capable processor.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"processor":{"type":"string","minLength":1},"redirect_uri":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["processor"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/connect-oauth","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"merchant_account_id":{},"next_step":{},"oauth_url":{},"processor":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.crm_disconnect","description":"Disconnect a CRM integration (soft-deactivate).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"integration_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["integration_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/crm-disconnect","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"integration_id":{},"provider":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.crm_list","description":"List all connected CRM integrations (HubSpot, Salesforce, Pipedrive, etc.).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/crm-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"integrations":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.crm_status","description":"Aggregated integration status across all categories — payments, CRM, accounting.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/crm-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"accounting_connections":{},"crm_integrations":{},"payment_processors":{},"summary":{},"total_integrations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.disconnect_processor","description":"Disconnect a payment processor. Promotes next account to default if needed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"merchant_account_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["merchant_account_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"540","noun":"merchant_account","acts_on":{"noun":"merchant_account","address":"540","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/disconnect-processor","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"processor":{},"promoted_new_default":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.doctor","description":"⭐ What is broken across this company's setup, worst first, each with the fix. Covers custom domains (DNS + certificate), connected AI provider keys and issued API keys. Ranked by what it COSTS the merchant — a domain that does not resolve means their site is down; a stale integration means a report is old — not by how easy it was to detect. ⛔ `unknown` means the check could not run and is NOT a pass: 'we could not check your SSL' and 'your SSL is fine' are different answers. Pass area= to narrow, include_ok=true to see what passed. Adds no probes of its own — every check comes from a verb that already existed.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"area":{"type":"string","enum":["domain","ai","credentials"],"nullable":true},"include_ok":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/doctor","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"checked":{},"counts":{},"findings":{},"headline":{},"note":{},"severity_meaning":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.list","description":"List all external integrations (OAuth providers + API keys) for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/list","http_method":"POST","dispatch_endpoint":null},{"name":"integration.list_available","description":"List all available payment/accounting/CRM integrations and which ones are connected for this company. Universal — covers every processor in the registry.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"91","noun":"integration","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/list-available","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"processors":{},"total_available":{},"total_connected":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.payment_status","description":"Check payment processor setup status — which processors are connected, which is default.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"540","noun":"merchant_account","acts_on":{"noun":"merchant_account","address":"540","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/payment-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connected_count":{},"default_processor":{},"has_payment_processor":{},"processors":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration.set_default_processor","description":"Set a connected payment processor as the default for this company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"merchant_account_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["merchant_account_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"540","noun":"merchant_account","acts_on":{"noun":"merchant_account","address":"540","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/integration/set-default-processor","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"is_default":{},"merchant_account_id":{},"processor":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"integration_list","description":"List all external integrations (OAuth providers + API keys) for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"91","noun":"integration","location":"svc.api","same_as":"integration.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"oauth_providers":{},"payment_processors":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.adjust","description":"Adjust stock-on-hand for a SKU by delta (positive to add, negative to subtract). Updates the most recent non-empty stock batch for the SKU. Reason is required for the audit trail (e.g. 'sale 1234', 'shrinkage Q3', 'manual recount'). Final quantity is clamped to ≥ 0 — negative deltas larger than current stock zero it out rather than going negative.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sku":{"type":"string","description":"Product SKU. Case-sensitive."},"delta":{"type":"integer","description":"Change in units. Positive=add, negative=subtract."},"reason":{"type":"string","description":"Audit reason. Required.","minLength":3,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["sku","delta","reason"]},"required_scope":"commerce:write","transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/adjust","http_method":"POST","dispatch_endpoint":null},{"name":"inventory.adjust_stock","description":"Adds quantity_change (negative to reduce) to a product's products.quantity_available. Has no location effect; location_id and reason are echoed only. Returns old and new quantity.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"quantity_change":{"type":"integer"},"location_id":{"type":"integer","nullable":true},"reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id","quantity_change"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/adjust-stock","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"change":{},"new_quantity":{},"old_quantity":{},"product_id":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.check","description":"Return current stock-on-hand for a product SKU. Sums available quantity across all stock batches for the SKU (excludes reserved + expired). Read-only. Returns 0 if the SKU has no stock OR doesn't exist for this company — DO NOT fabricate a number.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sku":{"type":"string","description":"Product SKU. Case-sensitive."}},"required":["sku"]},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/check","http_method":"POST","dispatch_endpoint":null},{"name":"inventory.create_location","description":"Creates a location (locations) with a slug derived from the name; address is stored as address_json line1 and location_type maps to kind physical or virtual. Returns location_id and slug.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"address":{"type":"string","nullable":true},"location_type":{"type":"string","default":"warehouse"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/create-location","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"address_json":{},"kind":{},"location_id":{},"location_type_requested":{},"name":{},"slug":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.cross_location_recommendation","description":"Per-location stock breakdown + best transfer source + recommendation.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"quantity":{"type":"integer","minimum":1},"target_location_id":{"type":"integer","nullable":true}},"required":["product_id","quantity"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/cross-location-recommendation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"best_transfer_source":{},"error":{},"error_code":{},"per_location":{},"product":{},"quantity_requested":{},"recommendation":{},"success":{},"target_location_id":{},"target_stock":{},"total_available_across_locations":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.explain_stockout","description":"Causal chain behind a product's stock level: sales / transfers / adjustments + velocity + projected runout. Stock sums across locations unless location_id is given. is_stocked_out is true, false, or null for \"never recorded\"; anything Solid# cannot see (goods-in has no model) is named in `unavailable`, never returned as an empty list.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"location_id":{"type":"integer","minimum":1,"nullable":true},"activity_limit":{"type":"integer","minimum":1,"maximum":100,"default":25}},"required":["product_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/explain-stockout","http_method":"POST","dispatch_endpoint":null},{"name":"inventory.import_csv","description":"Imports an inventory CSV onto this company's products, matched by SKU (exact, else one case-insensitive match). A found SKU gets only its non-blank cells written; a new SKU is created and needs a name. on_hand sets products.quantity_available, or, when the row has a location (id, slug or name), that location's stock_levels row with a stock_adjustments record. Prices arrive as price_basis 'unknown' unless given. Columns: sku, name, description, category, on_hand, price|price_cents, cost_per_unit|cost_cents, msrp, reorder_point, reorder_quantity, upc|ean|barcode, location, currency (USD), price_basis. dry_run performs the same writes and rolls them back, so its counts are the real outcome. Returns created/updated/unchanged counts, row_errors [{row, sku, error}] and ignored_columns.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"csv_text":{"type":"string","minLength":1,"description":"The CSV file's contents, header row first."},"dry_run":{"type":"boolean","default":false},"price_basis":{"type":"string","enum":["cash","card","unknown"],"nullable":true,"description":"Which prices the file holds on a two-price program. Omitted = 'unknown' until the owner confirms."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["csv_text"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/import-csv","http_method":"POST","dispatch_endpoint":null},{"name":"inventory.list_locations","description":"Lists the tenant's locations (locations table). Returns id and name per location plus total; address and type come back null because the model has no such columns.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/list-locations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"locations":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.preview_allocation","description":"Project per-line allocation of an order against a location's stock.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","minimum":1},"items":{"type":"array","minItems":1,"items":{"type":"object","properties":{"product_id":{"type":"integer"},"quantity":{"type":"integer","minimum":1}},"required":["product_id","quantity"]}}},"required":["location_id","items"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/preview-allocation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"lines":{},"location_id":{},"reasons":{},"success":{},"summary":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory.suggest_reorder","description":"Ranked reorder suggestions for a location.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer","minimum":1},"urgency_floor":{"type":"integer","minimum":0,"maximum":2,"default":0}},"required":["location_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/suggest-reorder","http_method":"POST","dispatch_endpoint":null},{"name":"inventory.transfer","description":"Transfer stock between two locations. Really creates a PENDING StockTransfer and moves the quantity into in-transit; it does not confirm receipt at the destination.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"from_location_id":{"type":"integer","minimum":1},"to_location_id":{"type":"integer","minimum":1},"quantity":{"type":"integer","minimum":1},"notes":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id","from_location_id","quantity","to_location_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"43","noun":"inventory","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/inventory/transfer","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"from_location_id":{},"note":{},"product_id":{},"quantity":{},"status":{},"summary":{},"to_location_id":{},"transfer_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory_adjust","description":"Adjust stock-on-hand for a SKU by delta (positive to add, negative to subtract). Updates the most recent non-empty stock batch for the SKU. Reason is required for the audit trail (e.g. 'sale 1234', 'shrinkage Q3', 'manual recount'). Final quantity is clamped to ≥ 0 — negative deltas larger than current stock zero it out rather than going negative.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sku":{"type":"string","description":"Product SKU. Case-sensitive."},"delta":{"type":"integer","description":"Change in units. Positive=add, negative=subtract."},"reason":{"type":"string","description":"Audit reason. Required.","minLength":3,"maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["sku","delta","reason"]},"required_scope":"commerce:write","transport":"dispatch","coordinate":"43","noun":"inventory","location":"svc.api","same_as":"inventory.adjust","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"batch_id":{},"clamped_at_zero":{},"delta_applied":{},"new_quantity_available":{},"note":{},"ok":{},"reason":{},"sku":{},"variant_id":{},"variant_name":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"inventory_check","description":"Return current stock-on-hand for a product SKU. Sums available quantity across all stock batches for the SKU (excludes reserved + expired). Read-only. Returns 0 if the SKU has no stock OR doesn't exist for this company — DO NOT fabricate a number.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"sku":{"type":"string","description":"Product SKU. Case-sensitive."}},"required":["sku"]},"required_scope":null,"transport":"dispatch","coordinate":"43","noun":"inventory","location":"svc.api","same_as":"inventory.check","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"found":{},"note":{},"ok":{},"quantity_available":{},"sku":{},"variant_id":{},"variant_name":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoice.cancel","description":"Cancel an invoice that should not be collected — with the reason, which stays on it. Nothing is deleted. Refused if money was already paid on it (record the refund first).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"reason":{"type":"string","minLength":3},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","reason"]},"required_scope":"payments:write","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_cancelled","when":"The invoice is already cancelled.","override":null,"code_in_response":true},{"code":"has_payments","when":"Money has been paid on it — record the refund first.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/cancel","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.get","description":"Accounts receivable — one invoice with its line items, its customer, and every payment recorded on it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1}},"required":["invoice_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/get","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.list","description":"Accounts receivable — the company's invoices to its own customers (the `invoices` table; not Solid#'s bills to the company). Filter by status, customer (contact_id), open_only, overdue_only, issue-date range, or `query` (number, customer name or email); `sort` newest (default), oldest, amount_high, amount_low, owed_high, due_date (most overdue first). Each row has days_overdue; `counts` gives all/owed/overdue/paid/cancelled. Amounts in dollars and cents.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","sent","viewed","partial_paid","paid","overdue","cancelled"]},"contact_id":{"type":"integer"},"open_only":{"type":"boolean"},"overdue_only":{"type":"boolean"},"since":{"type":"string","description":"YYYY-MM-DD"},"until":{"type":"string","description":"YYYY-MM-DD"},"query":{"type":"string","description":"invoice number, customer name or email"},"sort":{"type":"string","enum":["newest","oldest","amount_high","amount_low","owed_high","due_date"],"default":"newest"},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50},"offset":{"type":"integer","minimum":0,"default":0}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/list","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.outstanding_total","description":"Return the total amount of OPEN (unpaid) invoices for this company, in cents, plus a count. Used when Alex needs to answer 'how much AR do we have right now?'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"payments:read","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/outstanding-total","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.receivables","description":"Accounts receivable aging — what customers owe the business, by how overdue (not due, 1-30, 31-60, 61-90, 90+ days, no due date), with the soonest due. The twin of expense.payables.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"as_of":{"type":"string","description":"YYYY-MM-DD; default today"}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/receivables","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.refund_returned","description":"Mark the money a stopped job owed back to the customer as returned (the business already paid it back — cash, check, or a refund in their own processor). Nothing moves money here; it records that it was done, keeps the note on the invoice, and clears the Home card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"method":{"type":"string","description":"How it was returned: cash, check, card, other"},"note":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id"]},"required_scope":"payments:write","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/refund-returned","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.summary","description":"Money in, grouped by customer, month or status: invoiced, collected and still owed — reported separately, never added together. Period = issue date.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string"},"until":{"type":"string"},"group_by":{"type":"string","enum":["customer","month","status"],"default":"customer"}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/summary","http_method":"POST","dispatch_endpoint":null},{"name":"invoice.sync","description":"Send invoices (with their customer and anything paid on them) to the connected accounting system. With invoice_id it sends that one now and says how it landed: synced, excluded (issued before money in was switched on), or failed with the reason (a setting to choose, no customer, changed after it was sent). Without it, everything waiting is queued and each invoice shows its own status. Never enters an invoice twice.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice/sync","http_method":"POST","dispatch_endpoint":null},{"name":"invoice_bounce_check","description":"A check recorded on an invoice came back unpaid. Marks that payment bounced (it stays in the history), puts the amount back on what the customer owes, and re-opens the invoice. payment_id is the payment's transaction_id from the invoice's payments list.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"payment_id":{"type":"string","description":"The payment's transaction_id (invoice payments list)."},"reason":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","payment_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice_payment.bounce_check","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"invoice_cancel","description":"Cancel an invoice that should not be collected — with the reason, which stays on it. Nothing is deleted. Refused if money was already paid on it (record the refund first).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"reason":{"type":"string","minLength":3},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","reason"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice.cancel","status":"active","inverse":null,"refuses_when":[{"code":"already_cancelled","when":"The invoice is already cancelled.","override":null,"code_in_response":true},{"code":"has_payments","when":"Money has been paid on it — record the refund first.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"invoice_id":{},"invoice_number":{},"preview":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoice_payment.bounce_check","description":"A check recorded on an invoice came back unpaid. Marks that payment bounced (it stays in the history), puts the amount back on what the customer owes, and re-opens the invoice. payment_id is the payment's transaction_id from the invoice's payments list.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"payment_id":{"type":"string","description":"The payment's transaction_id (invoice payments list)."},"reason":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","payment_id"]},"required_scope":"payments:write","transport":"http","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice_payment/bounce-check","http_method":"POST","dispatch_endpoint":null},{"name":"invoice_payment.charge","description":"Charge a tenant invoice through the company's connected payment processor. Processor-agnostic — routes through services/payments/registry.py and the company's MerchantAccount. Requires admin role + typed-phrase confirmation including the amount and invoice number.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"ID of the tenant invoice to charge (invoices.id)."},"amount_cents":{"type":"integer","description":"Amount to charge in cents (must equal or be less than amount_due).","minimum":1},"source_token":{"type":"string","description":"Payment source token (card token, payment_method_id, etc.) from the processor — supplied by the frontend / saved on the customer."},"processor":{"type":"string","description":"Optional override of the company's default processor. Use only when explicitly directed; default uses MerchantAccount.is_default=True."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","amount_cents","source_token"]},"required_scope":"payments:write","transport":"http","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice_payment/charge","http_method":"POST","dispatch_endpoint":null},{"name":"invoice_payment.record_payment","description":"Record money a customer paid on an invoice — cash, a check, a transfer, Venmo, Zelle — with the date and the check or reference number. The invoice moves to partly paid or paid. Records it only; charges no one. Refuses more than is still owed, a draft, or a cancelled invoice. Works with or without an accounting system.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"amount":{"type":"number","exclusiveMinimum":0},"method":{"type":"string","enum":["cash","check","card","ach","bank_transfer","venmo","zelle","other"]},"received_at":{"type":"string","description":"YYYY-MM-DD; default today."},"reference":{"type":"string","description":"Check or confirmation number."},"check_number":{"type":"string","description":"For a check: its number (kept so a bounced check can be found)."},"tendered":{"type":"number","description":"For cash: what was handed over — the change due comes back."},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","amount"]},"required_scope":"payments:write","transport":"http","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invoice_draft","when":"The invoice has not been sent yet.","override":null,"code_in_response":true},{"code":"invoice_cancelled","when":"The invoice is cancelled.","override":null,"code_in_response":true},{"code":"more_than_owed","when":"The amount is more than what is due.","override":null,"code_in_response":true},{"code":"tendered_short","when":"Cash tendered is less than the amount (checked at execution).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/invoice_payment/record-payment","http_method":"POST","dispatch_endpoint":null},{"name":"invoice_record_payment","description":"Record money a customer paid on an invoice — cash, a check, a transfer, Venmo, Zelle — with the date and the check or reference number. The invoice moves to partly paid or paid. Records it only; charges no one. Refuses more than is still owed, a draft, or a cancelled invoice. Works with or without an accounting system.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"amount":{"type":"number","exclusiveMinimum":0},"method":{"type":"string","enum":["cash","check","card","ach","bank_transfer","venmo","zelle","other"]},"received_at":{"type":"string","description":"YYYY-MM-DD; default today."},"reference":{"type":"string","description":"Check or confirmation number."},"check_number":{"type":"string","description":"For a check: its number (kept so a bounced check can be found)."},"tendered":{"type":"number","description":"For cash: what was handed over — the change due comes back."},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id","amount"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"511","noun":"invoice_payment","acts_on":{"noun":"invoice_payment","address":"511","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice_payment.record_payment","status":"active","inverse":null,"refuses_when":[{"code":"invoice_draft","when":"The invoice has not been sent yet.","override":null,"code_in_response":true},{"code":"invoice_cancelled","when":"The invoice is cancelled.","override":null,"code_in_response":true},{"code":"more_than_owed","when":"The amount is more than what is due.","override":null,"code_in_response":true},{"code":"tendered_short","when":"Cash tendered is less than the amount (checked at execution).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount":{},"customer":{},"invoice_id":{},"invoice_number":{},"preview":{},"still_owed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoice_refund_returned","description":"Mark the money a stopped job owed back to the customer as returned (the business already paid it back — cash, check, or a refund in their own processor). Nothing moves money here; it records that it was done, keeps the note on the invoice, and clears the Home card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"method":{"type":"string","description":"How it was returned: cash, check, card, other"},"note":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice.refund_returned","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"invoice_sync","description":"Send invoices (with their customer and anything paid on them) to the connected accounting system. With invoice_id it sends that one now and says how it landed: synced, excluded (issued before money in was switched on), or failed with the reason (a setting to choose, no customer, changed after it was sent). Without it, everything waiting is queued and each invoice shows its own status. Never enters an invoice twice.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"dispatch","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice.sync","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"accounting_sync_status":{},"invoice_id":{},"invoice_ids":{},"invoice_number":{},"next":{},"preview":{},"provider":{},"queued":{},"total":{},"waiting":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoices_list","description":"List the SUBSCRIPTION INVOICES Solid# has issued TO this company — what this company owes Solid#, not what its own customers owe it. For a company's own customer invoices use `invoice.list`. Filter by status (draft / open / paid / void / uncollectible). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","open","paid","void","uncollectible"],"description":"Filter by invoice status."},"limit":{"type":"integer","description":"Max invoices (default 20)."}}},"required_scope":null,"transport":"dispatch","coordinate":"581","noun":"platform_invoice","acts_on":{"noun":"platform_invoice","address":"581","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"platform_invoice.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"invoices":{},"ok":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoices_mark_paid","description":"Solid# staff only: record that one of Solid#'s invoices to this company was paid outside the card on file (a check or ACH). Updates status='paid' and stamps paid_at=now; charges nothing. A company cannot mark its own bill from Solid# paid — its owner is told to contact Solid# billing. For the company's invoices to its own customers use invoice_record_payment.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"billing_invoices.id."},"note":{"type":"string","description":"Optional reconciliation note."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"581","noun":"platform_invoice","acts_on":{"noun":"platform_invoice","address":"581","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"platform_invoice.mark_paid","status":"active","inverse":null,"refuses_when":[{"code":"already_paid","when":"The billing invoice is already paid; answered as status already_paid, nothing changes.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_status":{},"invoice_id":{},"preflight":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"invoices_outstanding_total","description":"Return the total amount of OPEN (unpaid) invoices for this company, in cents, plus a count. Used when Alex needs to answer 'how much AR do we have right now?'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"invoice.outstanding_total","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"as_of":{},"company_id":{},"ok":{},"open_invoice_count":{},"outstanding_total_cents":{},"overdue_invoice_count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"issue_refund","description":"Refund a prior charge through the company's connected processor. Pass amount_cents to do a partial refund; omit for a full refund. IRREVERSIBLE — owner role only + typed phrase including the amount and charge id.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string","description":"The processor's charge id (returned by charge_invoice)."},"amount_cents":{"type":"integer","description":"Refund amount in cents. Omit for full refund.","minimum":1},"reason":{"type":"string","description":"Refund reason (stored in audit log).","maxLength":500},"processor":{"type":"string","description":"Optional processor override."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"531","noun":"refund","acts_on":{"noun":"refund","address":"531","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"refund.issue","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount_cents":{},"charge_id":{},"error":{},"error_code":{},"preflight":{},"processor":{},"refund_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"job.add_visit","description":"Book another visit for the same job through the one booking (appointment.book's rules — hours, time off, clashes): start_time (ISO), duration_minutes, staff_id (default: the job's first visit's person). The visit is linked to the job (job.get visits). The customer's confirmation goes only with tell_customer=true (default false).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"},"start_time":{"type":"string","description":"ISO start of the visit"},"duration_minutes":{"type":"integer","nullable":true},"staff_id":{"type":"integer","nullable":true,"description":"technicians.id; default the job's person"},"tell_customer":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["job_id","start_time"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/add-visit","http_method":"POST","dispatch_endpoint":null},{"name":"job.create","description":"Turn an approved (signed/accepted) estimate into a job — the estimate's own order runs the service_job lifecycle (scheduled → in_progress → completed → signed_off). Optionally books the visit with start_time (+ duration_minutes, staff_id; best-fit technician when none is named — job.suggest_staff ranks them) through the one booking, appointment.book. The customer is told the date ONLY when notify_customer=true (default false: the owner tells them). Idempotent: the same job comes back. No deposit gate — money is later. Progress is order.milestone (tech_dispatched, on_site, work_completed).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","minimum":1},"start_time":{"type":"string","nullable":true,"description":"ISO start of the visit"},"duration_minutes":{"type":"integer","nullable":true},"staff_id":{"type":"integer","nullable":true,"description":"technicians.id; omit for best fit"},"address":{"type":"string","nullable":true,"description":"where the work is; defaults to the customer's primary address"},"notify_customer":{"type":"boolean","default":false,"description":"send the customer the booking confirmation (default false)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_approved","when":"The estimate has not been accepted.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/create","http_method":"POST","dispatch_endpoint":null},{"name":"job.get","description":"One job sheet: customer, address, the visit (when, who), the work as a checklist from the signed estimate — no prices — notes, photo document ids, state, the sign-off record (without the image) and what can happen next.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"}},"required":["job_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/get","http_method":"POST","dispatch_endpoint":null},{"name":"job.list","description":"This company's jobs, soonest visit first, with how much of the work is ticked. Filter by states.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"states":{"type":"array","items":{"type":"string","enum":["scheduled","in_progress","on_hold","completed","signed_off","closed","cancelled"]},"nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/list","http_method":"POST","dispatch_endpoint":null},{"name":"job.pause","description":"Put a job on hold — reason parts | customer | weather | other, an optional note — recording why and since when; job.resume returns it to the state it was in. tell_customer=true sends the customer a short line (email; a text only while texting is registered) — default false. A job on hold for more than 3 days puts a card on Home.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"},"reason":{"type":"string","enum":["parts","customer","weather","other"]},"note":{"type":"string","nullable":true},"tell_customer":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["job_id","reason"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/pause","http_method":"POST","dispatch_endpoint":null},{"name":"job.resume","description":"Take a job off hold — back to the state it was paused from (scheduled or in progress). tell_customer=true tells the customer work is back on (default false).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"},"tell_customer":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["job_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/resume","http_method":"POST","dispatch_endpoint":null},{"name":"job.stop","description":"Stop a job early (reason customer_unhappy | cant_do | customer_cancelled | other) and settle the money honestly: bill=done makes the invoice the ticked checklist lines at their estimate prices; bill=amount bills one line 'Work completed to date' for `amount`; bill=nothing voids the invoice (kept, never deleted). Every payment stays. deposit=return records a refund OWED (what was paid beyond what is now billed) as a credit note and a Home card — no card refund is attempted; keep | none record nothing. Future visits are cancelled (the customer is told only with tell_customer). Returns {job, invoice {id, total, due, status}, refund_owed, appointments_cancelled}. The customer may then sign for the work done: POST /api/v1/jobs/{id}/sign-off with partial=true.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"},"reason":{"type":"string","enum":["customer_unhappy","cant_do","customer_cancelled","other"]},"note":{"type":"string","nullable":true},"bill":{"type":"string","enum":["done","amount","nothing"],"default":"done"},"amount":{"type":"number","nullable":true,"description":"with bill=amount: what to bill"},"deposit":{"type":"string","enum":["keep","return","none"],"default":"none"},"tell_customer":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["job_id","reason"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/stop","http_method":"POST","dispatch_endpoint":null},{"name":"job.suggest_staff","description":"Who should do an approved estimate's job, ranked best first with why ({staff_id, name, why, free, is_me}) — by the same rules a booking staffs by: working hours, time off, clashes and the daily cap when start_time is given; who saw this customer last, on call, rating. is_me marks the viewer's own team record. Read-only; book with job.create staff_id.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","minimum":1},"start_time":{"type":"string","nullable":true,"description":"ISO start of the visit (judge who is free then)"},"duration_minutes":{"type":"integer","nullable":true}},"required":["proposal_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/suggest-staff","http_method":"POST","dispatch_endpoint":null},{"name":"job.update","description":"Change a job sheet: tick a line of the work (check = the line's key, done true/false), add a note, attach a photo (photo_document_id, this company's file), or fix the address. Refused once the customer has signed off.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"job_id":{"type":"integer"},"check":{"type":"string","nullable":true},"done":{"type":"boolean","nullable":true},"note":{"type":"string","nullable":true},"photo_document_id":{"type":"integer","nullable":true},"address":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["job_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"362","noun":"job","acts_on":{"noun":"job","address":"362","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"job_final","when":"The job is signed off, closed or cancelled.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/job/update","http_method":"POST","dispatch_endpoint":null},{"name":"kb.contact_get","description":"Get full contact knowledge for context injection.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM Contact ID"}},"required":["contact_id"]},"required_scope":"kb:read","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/contact-get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"error":{},"knowledge":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.contact_learn","description":"Record what an agent learned in one interaction into a CRM contact's (crm_contacts id) contact-layer KB memory. Writes; AI notes are kept only if the contact consented to AI learning.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM Contact ID to update"},"interaction_summary":{"type":"string","description":"Brief summary of the interaction (1-2 sentences)"},"learned_preferences":{"type":"object","description":"Dict of preferences learned (e.g., {\"preferred_time\": \"mornings\"})"},"learned_properties":{"type":"array","description":"List of property details learned (for service businesses)"},"sentiment":{"type":"string","description":"Customer sentiment from interaction (positive/neutral/negative)"},"agent_type":{"type":"string","description":"Which AI agent is reporting (sarah, jake, marcus, etc.)"},"confidence":{"type":"number","description":"Confidence score for the learning (0.0-1.0)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","interaction_summary"]},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"skipped","when":"The contact asked for GDPR deletion, or has a KB entry without AI-learning consent; nothing is stored.","override":null,"code_in_response":true},{"code":"partial","when":"No KB entry and no AI-learning consent: only a basic CRM profile is stored, the AI notes are dropped.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/contact-learn","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"contact_id":{},"customer_tier":{},"error":{},"gdpr":{},"hint":{},"interaction_count":{},"last_sentiment":{},"notes_count":{},"reason":{},"sentiment_trend":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.contact_search","description":"Finds CRM contacts by their learned contact-layer KB traits (tier, churn risk, sentiment, preferred channel, LTV) or a text query over notes and names. Read-only; returns matches with a KB summary.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Natural language search (e.g., \"customers who prefer mornings\")"},"filters":{"type":"object","description":"Direct field filters (e.g., {\"customer_tier\": \"vip\"})"},"limit":{"type":"integer","description":"Max results to return"}}},"required_scope":"kb:read","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/contact-search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"count":{},"error":{},"filters":{},"limit":{},"query":{},"results":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.create_article","description":"Adds a help-centre article (kb_articles) to an existing category; tag names are matched or created as kb tags, meta_description becomes the SEO description. Returns article_id and slug.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"content":{"type":"string","minLength":1},"category_id":{"type":"integer","nullable":true},"status":{"type":"string","default":"draft"},"is_featured":{"type":"boolean","default":false},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"meta_description":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","title"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/create-article","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"article_id":{},"article_status":{},"featured":{},"reason":{},"slug":{},"status":{},"summary":{},"tag_ids":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.create_category","description":"Creates a help-centre category (kb_categories) with optional slug, icon, parent and sort order; slug is generated from the name if omitted. Requires name; returns category_id, name and slug.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"slug":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"icon":{"type":"string","nullable":true},"parent_id":{"type":"integer","nullable":true},"sort_order":{"type":"integer","default":0},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/create-category","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"category_id":{},"name":{},"slug":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.entry_create","description":"Create a new KB article (FAQ / policy / procedure). The user must provide a title and content; everything else is optional. Defaults to status='draft' — pass status='published' if the user confirmed it should go live immediately. Returns a confirmation card — the entry is NOT saved until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Headline of the article."},"content":{"type":"string","description":"Full body (markdown ok). Min 10 chars."},"category_id":{"type":"integer","description":"kb_categories.id this article belongs to."},"excerpt":{"type":"string","description":"Optional short summary (≤300 chars)."},"status":{"type":"string","enum":["draft","published"],"description":"Default 'draft'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","content","category_id"]},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/entry-create","http_method":"POST","dispatch_endpoint":null},{"name":"kb.entry_update","description":"Update an existing KB article. Pass only the fields to change (omit the rest). Useful for fixing stale procedure docs or retiring an entry by setting status='archived'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"article_id":{"type":"integer","description":"kb_articles.id to update."},"title":{"type":"string"},"content":{"type":"string"},"excerpt":{"type":"string"},"status":{"type":"string","enum":["draft","published","archived"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["article_id"]},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/entry-update","http_method":"POST","dispatch_endpoint":null},{"name":"kb.generate_article","description":"AI-write a draft help-centre article on a topic into an existing category_id; publishes only if auto_publish. Returns unsupported when AI generation is not configured.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"topic":{"type":"string","minLength":1},"category_id":{"type":"integer","nullable":true},"tone":{"type":"string","nullable":true},"auto_publish":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["topic"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"category_required","when":"category_id is missing; refused before any AI spend.","override":null,"code_in_response":true},{"code":"unsupported","when":"No AI client is configured, so nothing is written.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/generate-article","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.generate_from_product","description":"AI-write a draft \"How to use\" help-centre article from one of this company's products into an existing category_id. Returns unsupported when AI generation is not configured.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"category_id":{"type":"integer","nullable":true},"auto_publish":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/generate-from-product","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.publish","description":"Publish one or more knowledge base articles.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"article_ids":{"type":"array","items":{"type":"integer"},"minItems":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/publish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"published_count":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb.search","description":"Search this company's knowledge base and get back the matching articles — the answer to \"what are your hours\", \"do you do X\", \"what's your policy on Y\". Read-only. `customer_facing_only` defaults TRUE: an inbound phone caller is unauthenticated, so internal articles are excluded unless a caller with an identity explicitly asks otherwise. This is the SAME search the connector exposes as search_knowledge_base and ADA calls as knowledge_base_search — one implementation, now reachable from every surface including a live phone call.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":2},"limit":{"type":"integer","default":5,"maximum":20},"customer_facing_only":{"type":"boolean","default":true}},"required":["query"],"additionalProperties":true},"required_scope":"kb:read","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/search","http_method":"POST","dispatch_endpoint":null},{"name":"kb.search_entries","description":"Search this company's knowledge base by semantic similarity. Returns the top matching KB entries (questions, FAQs, policies, pricing, procedures). Use when the user asks 'what do we say about X' or 'do we have a policy on Y'. Read-only. Returns empty list if no entries match — do NOT fabricate answers from prior context.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Free-text search query. Vector-similarity matched.","minLength":2},"limit":{"type":"integer","description":"Max results to return. Default 5, max 20.","minimum":1,"maximum":20},"customer_facing_only":{"type":"boolean","description":"If true, only return entries marked ai_customer_visible=true (safe to paraphrase to a customer). Default false (internal + customer entries)."}},"required":["query"]},"required_scope":"kb:read","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/search-entries","http_method":"POST","dispatch_endpoint":null},{"name":"kb.update_article","description":"Update a help-centre article (kb_articles): title, content, category, status, featured flag, or tags by name (matched or created; replaces the set). Returns the fields applied.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"article_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"content":{"type":"string","nullable":true},"category_id":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"is_featured":{"type":"boolean","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["article_id"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"81","noun":"kb","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/kb/update-article","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"article_id":{},"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb_entry_create","description":"Create a new KB article (FAQ / policy / procedure). The user must provide a title and content; everything else is optional. Defaults to status='draft' — pass status='published' if the user confirmed it should go live immediately. Returns a confirmation card — the entry is NOT saved until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Headline of the article."},"content":{"type":"string","description":"Full body (markdown ok). Min 10 chars."},"category_id":{"type":"integer","description":"kb_categories.id this article belongs to."},"excerpt":{"type":"string","description":"Optional short summary (≤300 chars)."},"status":{"type":"string","enum":["draft","published"],"description":"Default 'draft'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","content","category_id"]},"required_scope":"kb:write","transport":"dispatch","coordinate":"81","noun":"kb","location":"svc.api","same_as":"kb.entry_create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"article_id":{},"category":{},"kb_status":{},"preflight":{},"slug":{},"status":{},"title":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"kb_entry_update","description":"Update an existing KB article. Pass only the fields to change (omit the rest). Useful for fixing stale procedure docs or retiring an entry by setting status='archived'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"article_id":{"type":"integer","description":"kb_articles.id to update."},"title":{"type":"string"},"content":{"type":"string"},"excerpt":{"type":"string"},"status":{"type":"string","enum":["draft","published","archived"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["article_id"]},"required_scope":"kb:write","transport":"dispatch","coordinate":"81","noun":"kb","location":"svc.api","same_as":"kb.entry_update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"article_id":{},"changes":{},"current_status":{},"kb_status":{},"preflight":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"key.rotate","description":"Rotate the company's outbound API key (used by external integrations to call back into Solid#). Old key is invalidated; new key returned ONCE. IRREVERSIBLE — copy the new key, the old one is dead. Typed phrase + owner.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"27","noun":"key","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/key/rotate","http_method":"POST","dispatch_endpoint":null},{"name":"knowledge_base_search","description":"Search this company's knowledge base by semantic similarity. Returns the top matching KB entries (questions, FAQs, policies, pricing, procedures). Use when the user asks 'what do we say about X' or 'do we have a policy on Y'. Read-only. Returns empty list if no entries match — do NOT fabricate answers from prior context.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Free-text search query. Vector-similarity matched.","minLength":2},"limit":{"type":"integer","description":"Max results to return. Default 5, max 20.","minimum":1,"maximum":20},"customer_facing_only":{"type":"boolean","description":"If true, only return entries marked ai_customer_visible=true (safe to paraphrase to a customer). Default false (internal + customer entries)."}},"required":["query"]},"required_scope":null,"transport":"dispatch","coordinate":"86","noun":"knowledge","location":"svc.api","same_as":"kb.search_entries","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"knowledge_graph.create_edge","description":"Create a relationship between two knowledge-graph nodes. Really writes the row; both endpoints are proved to belong to the calling tenant first.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"source_id":{"type":"integer","minimum":1},"target_id":{"type":"integer","minimum":1},"relationship":{"type":"string","minLength":1},"weight":{"type":"number","default":1.0},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["relationship","source_id","target_id"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"86","noun":"knowledge","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/knowledge_graph/create-edge","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"edge_id":{},"relationship":{},"source_id":{},"status":{},"target_id":{},"weight":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"knowledge_graph.create_node","description":"Create a node in the company knowledge graph. Really writes the row (label maps to graph_nodes.node_type).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"label":{"type":"string","minLength":1},"properties":{"type":"object"},"external_id":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["label","properties"],"additionalProperties":true},"required_scope":"kb:write","transport":"http","coordinate":"86","noun":"knowledge","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/knowledge_graph/create-node","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"node_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"knowledge_graph.question","description":"Search the knowledge graph and return MATCHING NODES. There is no natural-language answering layer — no answer is synthesised; the caller reasons over the matches.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"question":{"type":"string","minLength":1},"node_types":{"nullable":true,"type":"array","items":{"type":"string"}},"limit":{"type":"integer","minimum":1,"maximum":100,"default":10}},"required":["question"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"86","noun":"knowledge","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/knowledge_graph/question","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"match_count":{},"matches":{},"note":{},"question":{},"ranking":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"landing.create","description":"Creates an unpublished landing page (website_pages row, page_type landing) with title, optional slug, template and layout. Requires title; returns page_id and slug. Publish with landing.publish.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"template_id":{"type":"string","nullable":true},"slug":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"customizations":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"79","noun":"landing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/landing/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"is_published":{},"page_id":{},"slug":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"landing.publish","description":"Publishes a tenant landing page (website_pages, is_landing_page only) through the CMS publish pipeline with guardrails and snapshot. Requires page_id; returns published, or blocked with the reason.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"79","noun":"landing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"not_found","when":"The page is not a landing page — publish other pages with page.publish.","override":null,"code_in_response":true},{"code":"publish_requires_subscription","when":"The company has no active subscription.","override":null,"code_in_response":true},{"code":"blocked_by_guardrails","when":"Publishing is locked for the site, or the page is a Nest clone scored below the fidelity bar (no bypass on this verb).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/landing/publish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"page_id":{},"reason":{},"slug":{},"status":{},"summary":{},"title":{},"violations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"landing_create","description":"Create a new landing page (renders under /lp/ without nav/footer). Reversible.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Landing page title."},"template_id":{"type":"string","description":"Optional template id (default 'default')."},"slug":{"type":"string","description":"Optional slug; derived from the title if omitted."},"description":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"79","noun":"landing","location":"svc.api","same_as":"landing.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"landing_publish","description":"Publish a landing page by id (from landing_create). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"The landing page id to publish."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"79","noun":"landing","location":"svc.api","same_as":"landing.publish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"lead.suggest_assignment","description":"Rank agents to take ownership of a fresh lead.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","minimum":1},"agent_pool":{"type":"array","items":{"type":"integer"},"nullable":true},"top_k":{"type":"integer","minimum":1,"maximum":50,"default":5}},"required":["lead_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"lead","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/lead/suggest-assignment","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"lead_id":{},"reason":{},"success":{},"suggestions":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"level3.coverage","description":"Which products would fail Level 3 and what each is missing — a UPC or GS1 code qualifies strongest, a SKU qualifies weakly, nothing at all falls back to a placeholder that means nothing to an acquirer.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"553","noun":"interchange","acts_on":{"noun":"interchange","address":"553","domain":"Fees & pricing programmes","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/level3/coverage","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"best_code_upc_or_gs1":{},"failing":{},"no_product_code":{},"products_checked":{},"recommendation":{},"sku_only":{},"weak":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"level3.preview","description":"Exactly what Level 3 line detail would be sent for a sale, and whether it RECONCILES to the amount captured — detail that does not sum is rejected for Level 3 pricing, so the merchant pays the higher rate and the work was wasted. Names what each line is missing.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","nullable":true},"cart_id":{"type":"integer","nullable":true},"link_id":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"553","noun":"interchange","acts_on":{"noun":"interchange","address":"553","domain":"Fees & pricing programmes","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/level3/preview","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"found":{},"gap_cents":{},"level3":{},"line_count":{},"lines_missing_detail":{},"reconciles":{},"total_cents":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"line_release","description":"Release a phone line — stops the monthly rental (soft delete). Does NOT permanently release the number at the carrier (that stays a dashboard action). Reversible until the next billing run.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","description":"Phone line id to release."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id"]},"required_scope":"voice:write","transport":"dispatch","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"phone_line.release","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"line_set_routing_mode","description":"Set who answers a phone line: 'ring' (human first, AI backs up) · 'ask' (live decision) · 'ai' (AI answers) · 'off' (human only). ring/ask require a user assigned to the line.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","description":"Phone line id (from call_flow_get / switchboard)."},"routing_mode":{"type":"string","enum":["ring","ask","ai","off"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","routing_mode"]},"required_scope":"voice:write","transport":"dispatch","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"phone_line.set_routing_mode","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"link.cancel","description":"Stop a payment link being paid. Refuses on a link that has already been paid.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"link_id":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["link_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"link_already_paid","when":"The link has been paid (a cancelled or expired link is not refused).","override":null,"code_in_response":false}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/link/cancel","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"link_id":{},"ok":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"link.create","description":"Create a payment link and return the URL to send. Universal — the merchant's connected processor charges it. The URL always comes from the one builder that decides payment domains.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01},"description":{"type":"string","nullable":true},"customer_email":{"type":"string","nullable":true},"customer_phone":{"type":"string","nullable":true},"invoice_number":{"type":"string","nullable":true},"expires_in_hours":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/link/create","http_method":"POST","dispatch_endpoint":null},{"name":"link.status","description":"Has this payment link been paid? Tenant-scoped; another company's link reads as not found.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"link_id":{"type":"string","minLength":1}},"required":["link_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/link/status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"expires_at":{},"found":{},"link_id":{},"paid_at":{},"status":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_appointments_upcoming","description":"List upcoming appointments for this company in the next N days (default 7), from now, on the business's own clock. Excludes canceled and no-show. The SAME read as appointment_list (each row is the full appointment: customer, staff, series, allowed_actions; a clinic's patient visits too) plus the old keys (appointment_id, staff_id). Read-only. Use when the user asks 'what's on the calendar' or 'who's coming in this week'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":30,"description":"Default 7."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."}}},"required_scope":null,"transport":"dispatch","coordinate":"39","noun":"appointments","location":"svc.api","same_as":"appointment.upcoming","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"appointments":{},"company_id":{},"found":{},"ok":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_blog_posts","description":"List this company's blog posts. Filter by published state. Use when the user asks 'what posts are scheduled' or 'show me recent posts'. archived=true lists ONLY archived posts (restore one with blog_restore). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"published_only":{"type":"boolean","description":"Default false (drafts included)."},"archived":{"type":"boolean","description":"true = only archived posts. Default false."},"category":{"type":"string","description":"Optional category filter (exact match)."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Default 30."}}},"required_scope":"pages:read","transport":"dispatch","coordinate":"85","noun":"blog","location":"svc.api","same_as":"cms.blog.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"found":{},"ok":{},"posts":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_pages","description":"List this company's website pages. Filter by published state. Use when the user asks 'what pages do we have' or 'show me my drafts'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"published_only":{"type":"boolean","description":"If true, only is_published=true. If false (default), include drafts."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Default 30."}}},"required_scope":"pages:read","transport":"dispatch","coordinate":"79","noun":"pages","location":"svc.api","same_as":"page.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"found":{},"ok":{},"pages":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_pending_tasks","description":"List this company's open CRM tasks (status=pending or in_progress). Sorted by priority then due date. Default top 20. Use when the user asks 'what's on my plate' or 'show my open tasks'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."},"assigned_to_me":{"type":"boolean","description":"If true, only tasks assigned to the current user."}}},"required_scope":"crm:read","transport":"dispatch","coordinate":"99","noun":"tasks","location":"svc.api","same_as":"tasks.list_pending","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"found":{},"ok":{},"tasks":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_recent_calls","description":"List recent voice calls for this company — the most recent first. By default returns the latest calls regardless of age; pass `days` to limit to a recent window. Returns id, direction, from/to numbers, duration, status, summary preview. Read-only. Use when the user asks 'what calls came in' or 'show me last week's calls'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"description":"Optional lookback window in days. Omit to get the most recent calls regardless of age."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"Optional filter."},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."}}},"required_scope":"voice:read","transport":"dispatch","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"call.list_recent","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"calls":{},"company_id":{},"found":{},"ok":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"list_reviews","description":"This company's recent Google reviews and overall rating. Read-only. Use it to spot reviews that need a response or to gauge reputation.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Max reviews to return. Default 10."}}},"required_scope":null,"transport":"dispatch","coordinate":"39","noun":"reviews","location":"svc.api","same_as":"review.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"configured":{},"note":{},"ok":{},"rating":{},"review_count":{},"reviews":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm.connect","description":"Connect a BYO AI provider — add your own OpenAI, Anthropic, or Google API key.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider_type":{"type":"string","minLength":1},"api_key":{"type":"string","minLength":1},"name":{"type":"string","nullable":true},"config":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["api_key","provider_type"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/connect","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"has_api_key":{},"name":{},"provider_id":{},"provider_type":{},"status":{},"supported":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm.list_providers","description":"List connected LLM providers (OpenAI, Anthropic, Google, etc.) for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/list-providers","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"providers":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm.set_voice_key_source","description":"Choose who pays for this company's VOICE calls on a provider: its own stored API key (use_for_voice=true) or Solid#'s (false). Turning its own key on tests a real voice session first and refuses if the key cannot run voice; platform_backup lets a call continue on Solid#'s key if theirs is refused. Moves who pays — confirm with the owner.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider_type":{"type":"string","minLength":1,"description":"openai or xai (grok)"},"use_for_voice":{"type":"boolean"},"platform_backup":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["provider_type","use_for_voice"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"provider_not_connected","when":"No key of that provider is connected — llm.connect first.","override":null,"code_in_response":true},{"code":"refused","when":"The provider cannot run voice, its key is not active, or a live voice session could not be opened on it.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/set-voice-key-source","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm.spend_summary","description":"Summarize ADA's own LLM spend for this company over a time window, from the token_usage ledger. Returns total tokens, model breakdown, and approximate $ cost.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720}}},"required_scope":null,"transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/spend-summary","http_method":"POST","dispatch_endpoint":null},{"name":"llm.test_connection","description":"Test a connected LLM provider — verifies the API key works.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider_id":{"type":"integer","minimum":1}},"required":["provider_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/test-connection","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"provider_id":{},"provider_type":{},"status":{},"test_result":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm.usage","description":"Get LLM token usage summary for the company.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":30}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"14","noun":"llm","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/llm/usage","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"daily_usage":{},"period_days":{},"total_tokens":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"llm_spend_summary","description":"Summarize ADA's own LLM spend for this company over a time window, from the token_usage ledger. Returns total tokens, model breakdown, and approximate $ cost.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":720}}},"required_scope":null,"transport":"dispatch","coordinate":"14","noun":"llm","location":"svc.api","same_as":"llm.spend_summary","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"by_model":{},"since_hours":{},"total_cost_cents":{},"total_cost_display":{},"total_tokens":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"local_seo.fix_gap","description":"Local SEO — RECORD a gap as fixed (bookkeeping only; the directory listing itself is not changed). Company-scoped; raises if the gap is not this company's.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"gap_id":{"type":"integer","minimum":1},"fixed_by":{"type":"string","default":"agent"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["gap_id"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/local_seo/fix-gap","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"fixed_by":{},"gap_id":{},"note":{},"remediation_performed":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"local_seo.run_audit","description":"Local SEO — run the full listing audit (Scout, Sorter, Mapper, Inspector) and persist profile, categories, citations, gaps and rank map. Builder plan or higher; refuses system companies 1 and 2. Passing target_url raises — for a page crawl use seo.audit_run.","shape":"aggregate","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"business_name":{"nullable":true,"type":"string","description":"Defaults to the company name."},"address":{"nullable":true,"type":"string","description":"Defaults to the company business address."},"target_url":{"nullable":true,"type":"string","description":"Not supported — raises. Use seo.audit_run."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"system_company_refused","when":"Called from a system company.","override":null,"code_in_response":false},{"code":"target_url_unsupported","when":"A target_url was passed — this audits the business listing; use seo.audit_run for pages.","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/local_seo/run-audit","http_method":"POST","dispatch_endpoint":null},{"name":"mailbox.attachment_download","description":"Download a single attachment from a message. Returns base64 data + size + mime. Provider-agnostic.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message_id":{"type":"string"},"attachment_id":{"type":"string"},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_id","attachment_id"]},"required_scope":null,"transport":"http","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mailbox/attachment-download","http_method":"POST","dispatch_endpoint":null},{"name":"mailbox.list_unread","description":"List only unread messages. Convenience wrapper for email_read_recent(unread_only=True).","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":null,"transport":"http","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mailbox/list-unread","http_method":"POST","dispatch_endpoint":null},{"name":"mailbox.read_recent","description":"List recent inbox messages for triage. Provider-agnostic — routes through whichever inbox the company has connected (Gmail / Outlook / IMAP). Returns metadata + snippets only, no full bodies. Use email_thread_get for full content.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max messages. Default 25."},"unread_only":{"type":"boolean","description":"If true, only unread. Default false."},"query":{"type":"string","description":"Optional provider-native search query (Gmail q syntax, Outlook $filter, etc.)"},"provider":{"type":"string","description":"Optional provider override when the company has multiple inboxes."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":null,"transport":"http","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mailbox/read-recent","http_method":"POST","dispatch_endpoint":null},{"name":"mailbox.thread_get","description":"Get the full content of an inbox thread (all messages). Provider-agnostic. Use the thread_id returned by email_read_recent.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"thread_id":{"type":"string"},"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["thread_id"]},"required_scope":null,"transport":"http","coordinate":"641","noun":"mailbox","acts_on":{"noun":"mailbox","address":"641","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mailbox/thread-get","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.campaign_cohort_performance","description":"Cohort-level performance for an EmailCampaign.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","minimum":1}},"required":["campaign_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaign-cohort-performance","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign":{},"error":{},"error_code":{},"funnel":{},"ltv_proxy":{},"rates":{},"status_breakdown":{},"success":{},"totals":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.campaigns.add_recipients","description":"🤖 AI-POWERED: Add recipients to a campaign with intelligent targeting.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"},"contact_ids":{"type":"string","description":"Optional list of contact IDs"},"audience_filter":{"type":"string","description":"Optional filter (e.g., {\"tags\": [\"customer\"], \"source\": \"Website\"})"},"lead_score_min":{"type":"string","description":"Optional minimum lead score (0-100)"},"lead_score_max":{"type":"string","description":"Optional maximum lead score (0-100)"},"lead_tier":{"type":"string","description":"Optional lead tier filter ('hot', 'warm', 'cold')"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.add-recipients","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign_id":{},"message":{},"recipients_added":{},"targeting_criteria":{},"total_recipients":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.campaigns.create","description":"Create a draft email campaign in email_campaigns; requires name, subject, from_name, from_email, optional template_id or html/text content, reply_to and audience_filter. Returns id, name, status draft.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Campaign name"},"subject":{"type":"string","description":"Email subject line"},"from_name":{"type":"string","description":"Sender name"},"from_email":{"type":"string","description":"Sender email address"},"template_id":{"type":"string","description":"Optional email template ID"},"html_content":{"type":"string","description":"Optional HTML content (if not using template)"},"text_content":{"type":"string","description":"Optional plain text content"},"reply_to":{"type":"string","description":"Optional reply-to email"},"audience_filter":{"type":"string","description":"Optional audience filter (e.g., {\"tags\": [\"vip\"], \"status\": \"active\"})"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["from_email","from_name","name","subject"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"id":{},"message":{},"name":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.campaigns.delete","description":"Delete a campaign (only if draft or paused).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"campaign_not_deletable","when":"Only draft or paused campaigns can be deleted (same message as not-found).","override":null,"code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.delete","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.campaigns.get_stats","description":"Get detailed performance statistics for a campaign.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"}},"required":["campaign_id"]},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.get-stats","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.campaigns.list","description":"List the tenant's email campaigns from email_campaigns, optional status filter and limit. Returns each campaign's counts (recipients, sent, delivered, opened, clicked, bounced) with open and click rates.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","description":"Optional filter by status (draft, scheduled, sending, sent, paused, cancelled)"},"limit":{"type":"integer","description":"Maximum campaigns to return (default: 50)"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaigns":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.campaigns.schedule","description":"Schedule a draft or paused email campaign (email_campaigns) to send at an ISO scheduled_at; requires campaign_id. Sets status to scheduled; returns an error if the campaign is missing or in another state.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"},"scheduled_at":{"type":"string","description":"ISO 8601 datetime string (e.g., \"2025-10-15T10:00:00\")"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id","scheduled_at"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.schedule","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign_id":{},"error":{},"message":{},"scheduled_at":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.campaigns.send","description":"Send a campaign immediately or queue it for sending.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"},"send_now":{"type":"boolean","description":"If True, send immediately; if False, queue for background processing"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.send","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.campaigns.update","description":"Set fields on this company's email campaign (email_campaigns) by campaign_id — subject, content, sender and other columns; id, tenant and audit columns are never written. Returns campaign_id or not found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/campaigns.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign_id":{},"error":{},"message":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.segments_create","description":"Create a saved customer segment. Used when Marcus wants to snapshot a target audience for a campaign. Returns a confirmation card — the segment is NOT saved until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Segment name."},"description":{"type":"string","description":"Optional description."},"customer_count":{"type":"integer","description":"Initial customer count (the writer can refresh later)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/segments-create","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.segments_list","description":"List the company's customer segments (saved audiences). Returns segment name + customer count + last-refreshed timestamp. Use when Marcus needs to discuss campaign targeting or audience size. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max segments (default 20)."}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/segments-list","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.targeting.campaign_performance_by_tier","description":"🤖 AI-POWERED: Analyze campaign performance by lead tier.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"}},"required":["campaign_id"]},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.campaign-performance-by-tier","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.targeting.contacts_at_risk","description":"🤖 AI-POWERED: Get contacts with high churn risk.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"string","description":"Max contacts to return (default: 100)"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.contacts-at-risk","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_churn_risk":{},"contacts":{},"message":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.targeting.contacts_by_score","description":"🤖 AI-POWERED: Get contacts filtered by lead score range or tier.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"min_score":{"type":"integer","description":"Minimum lead score (0-100, default: 0)"},"max_score":{"type":"integer","description":"Maximum lead score (0-100, default: 100)"},"tier":{"type":"string","description":"Optional tier filter ('hot', 'warm', 'cold')"},"limit":{"type":"string","description":"Optional max contacts"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.contacts-by-score","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_ids":{},"criteria":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.targeting.contacts_for_nurture","description":"🤖 AI-POWERED: Get cold/warm contacts that need nurturing.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"string","description":"Max contacts to return (default: 200)"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.contacts-for-nurture","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_ids":{},"message":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.targeting.enrich_from_engagement","description":"🤖 AI-POWERED: Update lead score based on campaign engagement.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID"},"engagement_type":{"type":"string","description":"Type of engagement (email_open, email_click, unsubscribe, bounce)"}},"required":["contact_id","engagement_type"]},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.enrich-from-engagement","http_method":"POST","dispatch_endpoint":null},{"name":"marketing.targeting.high_value_contacts","description":"🤖 AI-POWERED: Get high-value contacts (hot tier, 80-100 score).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"string","description":"Max contacts to return (default: 50)"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/targeting.high-value-contacts","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_conversion_probability":{},"avg_score":{},"contacts":{},"message":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.workflow.auto_nurture_cold_leads","description":"🤖 FULL INTEGRATION: Auto-enroll cold leads in nurture drip sequence.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"max_contacts":{"type":"integer","description":"Maximum contacts to enroll (default: 500)"},"drip_sequence_id":{"type":"string","description":"Optional specific drip sequence ID"}}},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/workflow.auto-nurture-cold-leads","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"cold_leads_found":{},"contact_ids":{},"drip_sequence_id":{},"enrolled_count":{},"error":{},"message":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.workflow.campaign_performance_enriched","description":"🤖 FULL INTEGRATION: Analyze campaign + Enrich lead scores from engagement.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_id":{"type":"integer","description":"Campaign ID"}},"required":["campaign_id"]},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/workflow.campaign-performance-enriched","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"campaign_id":{},"enrichment":{},"error":{},"metrics":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.workflow.create_targeted_campaign","description":"🤖 FULL INTEGRATION: Generate AI content + Target by lead score + Sendcampaign.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"campaign_name":{"type":"string","description":"Campaign name"},"campaign_type":{"type":"string","description":"Type (promotional, welcome, newsletter, follow_up)"},"target_tier":{"type":"string","description":"Lead tier to target ('hot', 'warm', 'cold', or 'all')"},"message":{"type":"string","description":"Core message for AI to generate content around"},"from_name":{"type":"string","description":"Sender name"},"from_email":{"type":"string","description":"Sender email"},"send_immediately":{"type":"boolean","description":"Send now (default: False)"},"scheduled_at":{"type":"string","description":"Optional ISO 8601 datetime for scheduling"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["campaign_name","campaign_type","from_email","from_name","message","target_tier"]},"required_scope":"marketing:write","transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/workflow.create-targeted-campaign","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ai_generation_time_ms":{},"campaign_id":{},"content":{},"error":{},"recipients":{},"scheduled_at":{},"status":{},"success":{},"template_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing.workflow.personalized_email_by_score","description":"🤖 FULL INTEGRATION: Generate personalized email content based on lead score.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"Contact ID"},"message_theme":{"type":"string","description":"Theme/topic of the message"},"from_name":{"type":"string","description":"Sender name"},"from_email":{"type":"string","description":"Sender email"}},"required":["contact_id","from_email","from_name","message_theme"]},"required_scope":null,"transport":"http","coordinate":"98","noun":"marketing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketing/workflow.personalized-email-by-score","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"content":{},"error":{},"from_email":{},"from_name":{},"lead_score":{},"success":{},"tier":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing_campaigns_list","description":"List the company's recent email campaigns with delivery, open, click and unsubscribe counts. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max campaigns (default 20)."},"status":{"type":"string","description":"Filter by status (draft / scheduled / sent / paused)."}}},"required_scope":null,"transport":"dispatch","coordinate":"98","noun":"marketing","location":"svc.api","same_as":"marketing.campaigns.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing_segment_create","description":"Create a saved customer segment. Used when Marcus wants to snapshot a target audience for a campaign. Returns a confirmation card — the segment is NOT saved until the user clicks Confirm.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Segment name."},"description":{"type":"string","description":"Optional description."},"customer_count":{"type":"integer","description":"Initial customer count (the writer can refresh later)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"98","noun":"marketing","location":"svc.api","same_as":"marketing.segments_create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"name":{},"preflight":{},"segment_id":{},"status":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketing_segments_list","description":"List the company's customer segments (saved audiences). Returns segment name + customer count + last-refreshed timestamp. Use when Marcus needs to discuss campaign targeting or audience size. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max segments (default 20)."}}},"required_scope":null,"transport":"dispatch","coordinate":"98","noun":"marketing","location":"svc.api","same_as":"marketing.segments_list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"segments":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketplace.disable","description":"Marketplace — remove this company from the AI Marketplace and unpublish every staged product and service. Reports real unpublished counts.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"46","noun":"marketplace","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketplace/disable","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"marketplace_enabled":{},"products_unpublished":{},"services_unpublished":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketplace.enable","description":"Marketplace — make this company's catalogue discoverable in the AI Marketplace (sets Company.marketplace_enabled).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"46","noun":"marketplace","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketplace/enable","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"marketplace_enabled":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketplace.publish_all","description":"Marketplace — publish all products and services. Returns real synced/failed counts, not a flat success. Raises if the marketplace is not enabled.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"46","noun":"marketplace","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketplace/publish-all","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"products_failed":{},"products_synced":{},"services_failed":{},"services_synced":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketplace.publish_product","description":"Marketplace — publish one product. Raises if the marketplace is not enabled or the product belongs to another company.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"46","noun":"marketplace","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketplace/publish-product","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"product_id":{},"public_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"marketplace.unpublish_product","description":"Marketplace — unpublish one product from the AI Marketplace.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"46","noun":"marketplace","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/marketplace/unpublish-product","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"product_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"mission.dispatch_all","description":"Dispatch a multi-step mission across one or more agents. Each step is enqueued in order; steps DO NOT chain on each other's results (use send_agent_message inside steps for that). Returns the list of celery_task_ids for tracking. Use for parallel work like 'Sarah call the customer, Marcus draft the campaign, Emma write the follow-up email'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"steps":{"type":"array","description":"List of mission steps, each with target_agent_type or target_agent_id + task + optional context. Max 10 steps.","minItems":1,"maxItems":10,"items":{"type":"object","properties":{"target_agent_type":{"type":"string"},"target_agent_id":{"type":"integer"},"task":{"type":"string","minLength":1,"maxLength":4000},"context":{"type":"object"}},"required":["task"]}},"mission_label":{"type":"string","description":"Optional human-readable label for the mission.","maxLength":140},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal' — applies to every step."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["steps"]},"required_scope":"agents:write","transport":"http","coordinate":"19","noun":"mission","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mission/dispatch-all","http_method":"POST","dispatch_endpoint":null},{"name":"mission.dispatch_step","description":"Enqueue a single task on a target agent. The receiving agent is run through the full ConversationManager pipeline (system prompt + tools + KB + SKB). Returns a celery_task_id for polling result via /api/v1/agents/task/{id}. Use for one-off delegations; for multi-step missions use mission_dispatch_all.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Receiver agent_type from registry. Preferred."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"task":{"type":"string","description":"The task description / instruction. 1-4000 chars.","minLength":1,"maxLength":4000},"context":{"type":"object","description":"Optional context dict passed to the agent."},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task"]},"required_scope":"agents:write","transport":"http","coordinate":"19","noun":"mission","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/mission/dispatch-step","http_method":"POST","dispatch_endpoint":null},{"name":"mission_dispatch_all","description":"Dispatch a multi-step mission across one or more agents. Each step is enqueued in order; steps DO NOT chain on each other's results (use send_agent_message inside steps for that). Returns the list of celery_task_ids for tracking. Use for parallel work like 'Sarah call the customer, Marcus draft the campaign, Emma write the follow-up email'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"steps":{"type":"array","description":"List of mission steps, each with target_agent_type or target_agent_id + task + optional context. Max 10 steps.","minItems":1,"maxItems":10,"items":{"type":"object","properties":{"target_agent_type":{"type":"string"},"target_agent_id":{"type":"integer"},"task":{"type":"string","minLength":1,"maxLength":4000},"context":{"type":"object"}},"required":["task"]}},"mission_label":{"type":"string","description":"Optional human-readable label for the mission.","maxLength":140},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal' — applies to every step."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["steps"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"19","noun":"mission","location":"svc.api","same_as":"mission.dispatch_all","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agents":{},"audit_id":{},"message":{},"mission_label":{},"preflight":{},"priority":{},"status":{},"step_count":{},"steps":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"mission_dispatch_step","description":"Enqueue a single task on a target agent. The receiving agent is run through the full ConversationManager pipeline (system prompt + tools + KB + SKB). Returns a celery_task_id for polling result via /api/v1/agents/task/{id}. Use for one-off delegations; for multi-step missions use mission_dispatch_all.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Receiver agent_type from registry. Preferred."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"task":{"type":"string","description":"The task description / instruction. 1-4000 chars.","minLength":1,"maxLength":4000},"context":{"type":"object","description":"Optional context dict passed to the agent."},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal'."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["task"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"19","noun":"mission","location":"svc.api","same_as":"mission.dispatch_step","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"celery_task_id":{},"message":{},"preflight":{},"priority":{},"status":{},"to_agent":{},"to_agent_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"module.deploy","description":"Deploy a custom module to live — NOT executable from an agent surface; always raises. Custom modules run real code inside the backend process, so this stays on the authenticated developer flow: POST /api/v1/sandbox/deploy (`solid dev deploy`).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["folder_name"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/deploy","http_method":"POST","dispatch_endpoint":null},{"name":"module.disable","description":"Disable a custom module — NOT executable from an agent surface; always raises. Custom modules run real code inside the backend process, so this stays on the authenticated developer flow: POST /api/v1/sandbox/disable/{company_id}/{module_name}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["folder_name"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/disable","http_method":"POST","dispatch_endpoint":null},{"name":"module.enable","description":"Enable a custom module — NOT executable from an agent surface; always raises. Enabling loads the module's code into the live process: POST /api/v1/sandbox/deploy validates and enables in one step (`solid dev deploy`).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["folder_name"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/enable","http_method":"POST","dispatch_endpoint":null},{"name":"module.rollback","description":"Rollback a custom module to a previous version. Auto-snapshots current state before restoring.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"version":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["folder_name","version"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"module.scaffold","description":"Scaffold a custom module — NOT executable from an agent surface; always raises. Custom modules run real code inside the backend process, so this stays on the authenticated developer flow: POST /api/v1/sandbox/create (`solid dev create`).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"template":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/scaffold","http_method":"POST","dispatch_endpoint":null},{"name":"module.snapshot","description":"Create a named snapshot of a custom module before making changes.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"message":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["folder_name"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/snapshot","http_method":"POST","dispatch_endpoint":null},{"name":"module.versions","description":"List version history for a custom module.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"folder_name":{"type":"string","minLength":1},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"required":["folder_name"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"02","noun":"module","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/module/versions","http_method":"POST","dispatch_endpoint":null},{"name":"nest.archive","description":"Archive a Nest import (keeps the record, hides from default lists). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/archive","http_method":"POST","dispatch_endpoint":null},{"name":"nest.classify","description":"Dry-run a website clone: classify HTML or code and see what Nest would make of it without storing an import at all. Use nest.import when you actually want the preview you can execute.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string"},"format_hint":{"type":"string","nullable":true}},"required":["code"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/classify","http_method":"POST","dispatch_endpoint":null},{"name":"nest.delete","description":"Permanently delete a Nest import. Tenant-scoped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/delete","http_method":"POST","dispatch_endpoint":null},{"name":"nest.execute","description":"Step 2 of the clone: build what nest.import / nest.import_url previewed — creates the pages, widgets, flows and knowledge the imported website needs, wires the destination, records the outcome. Idempotent by import_id. Then nest.promote to place it on a real site.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"modifications":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/execute","http_method":"POST","dispatch_endpoint":null},{"name":"nest.fidelity","description":"Prove the clone matches: score the page an import built against the site the client actually gave us — content (every headline, price, phone, CTA), style (typefaces, palette, radii), motion (animations and interactive controls) and, with a browser, layout at 390/768/1440. Returns 0-100 per dimension, an overall score and the misses by element. The owner never has to eyeball a before/after.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"accept_fidelity":{"type":"integer","nullable":true}},"required":["import_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/fidelity","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"next":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"nest.get","description":"Fetch one website clone / Nest import by id — its status, warnings, what it created and the next step in the clone flow.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"}},"required":["import_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"nest.import","description":"THE ONE DOOR for cloning a website the business already has, when you are HOLDING ITS CODE — a single .html file, a folder of pages and stylesheets from a designer, or markup pasted in. Nest classifies it and returns a preview to approve. This is what 'import my website file', 'copy this HTML into my site', 'rebuild / recreate our old homepage from this code' and 'use the folder my developer sent as our website' all mean. Preview only — nothing is created until nest.execute. Have a live URL instead? Use nest.import_url, the same door.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string","nullable":true},"files":{"type":"array","nullable":true,"description":"A folder, relative paths kept: [{path, content, encoding?}]."},"archive_b64":{"type":"string","nullable":true,"description":"The same folder as a base64 zip."},"entry":{"type":"string","nullable":true,"description":"Which HTML file in the bundle is the page. Asked for, never guessed."},"inline_scripts":{"type":"boolean","default":false},"all_pages":{"type":"boolean","default":false,"description":"Folder only: import EVERY page as the site — the entry is home, each other page lands on its own slug, links between them rewritten."},"format_hint":{"type":"string","nullable":true},"source_url":{"type":"string","nullable":true},"source_hint":{"type":"string","nullable":true},"options":{"type":"object","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/import","http_method":"POST","dispatch_endpoint":null},{"name":"nest.import_url","description":"THE ONE DOOR for cloning a website the business already has, when you have its ADDRESS. Give the URL and Nest fetches the live site, classifies it and returns a preview to approve. This is what 'clone this website', 'copy my existing site into Solid#', 'duplicate our homepage', 'recreate my old website', 'move / migrate / bring my site across from Wix, Squarespace, GoDaddy, Wordpress', 'rebuild what we already have online' and 'start from my current site instead of a blank template' all mean. Preview only — nothing is created until nest.execute. Holding the HTML or a file instead of a URL? Use nest.import, the same door.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"url":{"type":"string"},"options":{"type":"object","nullable":true}},"required":["url"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/import-url","http_method":"POST","dispatch_endpoint":null},{"name":"nest.list","description":"List this tenant's website clones / imports — their status (preview, completed, promoted, rolled back) and ids to pass to nest.get, nest.execute or nest.promote.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20},"offset":{"type":"integer","minimum":0,"default":0}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/list","http_method":"POST","dispatch_endpoint":null},{"name":"nest.outcomes","description":"List the outcomes of executed Nest imports for the tenant.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/outcomes","http_method":"POST","dispatch_endpoint":null},{"name":"nest.promote","description":"Step 3 of the clone: place a built Nest import on a real site — off the sandbox and onto the tenant's site, subdomain or custom domain, still as a draft. Publishing stays a separate explicit step (page.publish). Wrong result? nest.rollback undoes the whole import.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"destination":{"type":"object","nullable":true},"accept_fidelity":{"type":"integer","nullable":true,"description":"Take a conversion scoring below the fidelity floor deliberately."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/promote","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"import_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"nest.rollback","description":"Undo a website clone: removes every entity a Nest import created (pages, widgets, flows, staged brand). The safety net behind nest.execute / nest.promote — the reason a clone can be tried without risk.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"nest.unarchive","description":"Restore an archived Nest import (ant_imports row, by import_id) to the default import history view by clearing its archived flag. Returns the import_id and is_archived=false.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"import_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["import_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"00","noun":"nest","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/nest/unarchive","http_method":"POST","dispatch_endpoint":null},{"name":"notes.add","description":"Add a work note that persists across sessions and AI models. Auto-embeds for semantic search. An AI cannot pin: is_pinned=true is saved unpinned with pin_refused (only the owner pins, from the dashboard).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"content":{"type":"string","minLength":1},"title":{"type":"string","nullable":true},"note_type":{"type":"string","default":"context"},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"related_entity_type":{"type":"string","nullable":true},"related_entity_id":{"type":"integer","nullable":true},"source":{"type":"string","default":"agent"},"importance":{"type":"integer","minimum":1,"maximum":10,"default":5},"is_pinned":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"pin_refused","when":"An AI asked to pin the note; it is saved unpinned and pin_refused=true.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/add","http_method":"POST","dispatch_endpoint":null},{"name":"notes.archive","description":"Archive a work note (soft-delete — hidden from default queries but recoverable).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["note_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/archive","http_method":"POST","dispatch_endpoint":null},{"name":"notes.context","description":"Get structured work context for session bootstrapping — pinned + high-importance + recent notes. Call this FIRST when starting a new session to pick up where the previous AI left off.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":20}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/context","http_method":"POST","dispatch_endpoint":null},{"name":"notes.get","description":"Reads one of the tenant's work notes (tenant_work_notes) by note_id. Returns the note's title, content, type, tags, importance and linked entity, or not_found.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_id":{"type":"integer","minimum":1}},"required":["note_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/get","http_method":"POST","dispatch_endpoint":null},{"name":"notes.list","description":"List work notes filtered by type, tags, or related entity. Pinned first, then by importance.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_type":{"type":"string","nullable":true},"related_entity_type":{"type":"string","nullable":true},"related_entity_id":{"type":"integer","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/list","http_method":"POST","dispatch_endpoint":null},{"name":"notes.search","description":"Semantic search across work notes using vector similarity. Falls back to keyword if embeddings unavailable.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":1},"limit":{"type":"integer","minimum":1,"maximum":100,"default":20}},"required":["query"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/search","http_method":"POST","dispatch_endpoint":null},{"name":"notes.update","description":"Update a work note. Re-embeds if content changes. Can unpin but never pin (owner only); editing the text of an owner-pinned note unpins it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"note_id":{"type":"integer","minimum":1},"content":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"},"nullable":true},"importance":{"type":"integer","nullable":true},"is_pinned":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["note_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"82","noun":"notes","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notes/update","http_method":"POST","dispatch_endpoint":null},{"name":"notification.mark_all_read","description":"Notification — mark every one of YOUR unread notifications as read, and report how many. The user is the caller, from the session; there is deliberately no company-wide sweep.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"681","noun":"notification","acts_on":{"noun":"notification","address":"681","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notification/mark-all-read","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"marked_read":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"notification.mark_read","description":"Notification — mark one of YOUR in-app notifications as read. Notifications are per-user; the user is the caller, from the session, and the row is resolved under both company_id and that user.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"notification_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["notification_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"681","noun":"notification","acts_on":{"noun":"notification","address":"681","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notification/mark-read","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"notification_id":{},"read_at":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"notification.subscribe_push","description":"Notification — register a browser Web Push subscription. NOT EXECUTABLE from an agent surface; always raises. A subscription is minted by the subscriber's own browser and must bind to that session — use POST /api/v1/notifications/push/subscribe.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["subscription"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"681","noun":"notification","acts_on":{"noun":"notification","address":"681","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/notification/subscribe-push","http_method":"POST","dispatch_endpoint":null},{"name":"oauth.revoke","description":"Revoke a connected OAuth integration (provider name like 'google', 'microsoft', 'linkedin'). IRREVERSIBLE — user must re-connect to restore. Typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["provider"]},"required_scope":"integrations:write","transport":"http","coordinate":"28","noun":"oauth","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/oauth/revoke","http_method":"POST","dispatch_endpoint":null},{"name":"oauth_revoke","description":"Revoke a connected OAuth integration (provider name like 'google', 'microsoft', 'linkedin'). IRREVERSIBLE — user must re-connect to restore. Typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"provider":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["provider"]},"required_scope":"integrations:write","transport":"dispatch","coordinate":"28","noun":"oauth","location":"svc.api","same_as":"oauth.revoke","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preflight":{},"provider":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"offer.available","description":"Live offers this company can honestly make right now — respects active flags, date windows, minimum spend and exclusive groups. intent='recover' picks the largest make-good for a customer who had a bad experience. Returns none rather than inventing one.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subtotal":{"type":"number","nullable":true},"scope":{"type":"string","nullable":true},"intent":{"type":"string","default":"promote"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"97","noun":"offer","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/offer/available","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"count":{},"intent":{},"offers":{},"recommended":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"offer.get","description":"The full deal, in one shape, from a cart, an order or a payment link: line items with SKUs and unit prices, tax, fees, the disclosure the merchant must show, the total, the currency, who the merchant is, and when the quote goes stale. Priced by the same engine that prices the card, so the quoted total IS the charged total. Read this before agreeing to pay anything.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cart_id":{"type":"integer","nullable":true},"order_id":{"type":"integer","nullable":true},"link_id":{"type":"string","nullable":true},"channel":{"type":"string","nullable":true},"tender":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"97","noun":"offer","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/offer/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"found":{},"offer":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.calculate_totals","description":"An order's total, priced the way the register will actually charge it — the merchant's fee programme (surcharge / dual pricing / cash discount / convenience fee) included, from the same engine the checkout uses. ⛔ Read `price_options` before quoting a price: where the programme posts TWO prices (cash and card) an agent that names one has quoted half the offer. `disclosure` is the wording that must accompany the number. The tip is never in the fee base — it is the employee's money.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"tip_percentage":{"type":"number","nullable":true},"donation_amount":{"type":"number","nullable":true},"tender":{"type":"string","enum":["card","cash","ach","check","other"],"default":"card"},"card_type":{"type":"string","enum":["credit","debit","prepaid","unknown"],"default":"unknown","description":"Debit and prepaid are never surcharged; the engine enforces that."},"card_brand":{"type":"string","nullable":true},"channel":{"type":"string","enum":["in_person","online","phone","invoice"],"default":"online"}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/calculate-totals","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"compliance":{},"disclosure":{},"donation":{},"fee":{},"fee_label":{},"fee_program":{},"order_id":{},"price_options":{},"status":{},"subtotal":{},"tax":{},"tip":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.cancel","description":"Cancel an order. Releases any held inventory.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/cancel","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"order_id":{},"reason":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.complete_fulfillment_state","description":"Order + items + allocations + reservations + ledger entries.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/complete-fulfillment-state","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"allocations":{},"error":{},"error_code":{},"items":{},"ledger_entries":{},"order":{},"reservations":{},"success":{},"summary":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.confirm","description":"Sets a tenant order (orders) to status confirmed; no payment is taken. Requires order_id; returns confirmed with the amount, already_confirmed, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/confirm","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"order_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.create","description":"Creates a pending order (orders) for one product and quantity, optionally linked to a CRM contact; amount defaults to product price x qty. Requires product_id; returns order_id, product name and amount.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"qty":{"type":"integer","minimum":1,"default":1},"amount":{"type":"number","nullable":true},"contact_id":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"order_id":{},"product":{},"qty":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.fulfill","description":"Sets a tenant order (orders) to status fulfilled; it does not ship anything or touch inventory. Requires order_id; returns fulfilled, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/fulfill","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"order_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.fulfillment_update","description":"Move an order's fulfillment_status forward (Jordan's main write). Accepts every workflow's canonical state vocabulary. The backend doesn't validate the transition — Jordan/the user is expected to know the right next state. Returns a confirmation card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"to_status":{"type":"string","description":"Target fulfillment_status."},"note":{"type":"string","description":"Optional note recorded with the transition."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","to_status"]},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/fulfillment-update","http_method":"POST","dispatch_endpoint":null},{"name":"order.list","description":"List orders for this company. Filter by fulfillment_status (unfulfilled / processing / fulfilled / shipped / delivered / cancelled) or workflow_type. Returns order ID, customer, amount, status. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"fulfillment_status":{"type":"string","description":"Filter by fulfillment status."},"limit":{"type":"integer","description":"Max orders (default 20)."}}},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/list","http_method":"POST","dispatch_endpoint":null},{"name":"order.milestone","description":"Report progress on an order — picking ticket created, picked, packed, shipping label created, handed to carrier, delivered, exception. Lands in the stream event.subscribe already reads. Some milestones advance the lifecycle state and some do not: shipping_label_created is NOT shipped, so read state_changed in the reply rather than assuming.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"milestone":{"type":"string","minLength":1},"detail":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","milestone"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/milestone","http_method":"POST","dispatch_endpoint":null},{"name":"order.milestones","description":"What progress can be reported on an order and what each milestone means. Filter by workflow_type — a picking ticket is meaningless on a subscription.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_type":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/milestones","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"milestones":{},"workflow_type":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.open_count","description":"Count orders that are NOT yet fulfilled / delivered / cancelled. Useful when Jordan needs to answer 'how much work is in the queue?'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/open-count","http_method":"POST","dispatch_endpoint":null},{"name":"order.progress","description":"Where an order actually is: the lifecycle state plus the milestones under it with timestamps, what is still outstanding, and the most recent thing that can truthfully be told to the customer. Use this rather than reading the status word on its own.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/progress","http_method":"POST","dispatch_endpoint":null},{"name":"order.quick_sale","description":"A quick sale is not executable from an agent surface — it is rung up at the counter (POS screen, POST /api/v1/orders/quick-sale). Record an order with order.create.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount":{"type":"number","minimum":0.01},"customer_name":{"type":"string","minLength":1},"customer_email":{"type":"string","nullable":true},"customer_phone":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"channel":{"type":"string","default":"ai"},"contact_id":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount","customer_name"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/quick-sale","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"channel":{},"customer_name":{},"order_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"order.refund","description":"Refund an order. Full refund if no amount specified.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer","minimum":1},"amount":{"type":"number","nullable":true},"reason":{"type":"string","default":"Customer request"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"42","noun":"order","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/order/refund","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"full_refund":{},"order_id":{},"refund_amount":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"orders_fulfillment_update","description":"Move an order's fulfillment_status forward (Jordan's main write). Accepts every workflow's canonical state vocabulary. The backend doesn't validate the transition — Jordan/the user is expected to know the right next state. Returns a confirmation card.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"order_id":{"type":"integer"},"to_status":{"type":"string","description":"Target fulfillment_status."},"note":{"type":"string","description":"Optional note recorded with the transition."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["order_id","to_status"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"49","noun":"orders","location":"svc.api","same_as":"order.fulfillment_update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_status":{},"from":{},"order_id":{},"preflight":{},"status":{},"to":{},"to_status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"orders_list","description":"List orders for this company. Filter by fulfillment_status (unfulfilled / processing / fulfilled / shipped / delivered / cancelled) or workflow_type. Returns order ID, customer, amount, status. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"fulfillment_status":{"type":"string","description":"Filter by fulfillment status."},"limit":{"type":"integer","description":"Max orders (default 20)."}}},"required_scope":null,"transport":"dispatch","coordinate":"49","noun":"orders","location":"svc.api","same_as":"order.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"orders":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"orders_open_count","description":"Count orders that are NOT yet fulfilled / delivered / cancelled. Useful when Jordan needs to answer 'how much work is in the queue?'. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"49","noun":"orders","location":"svc.api","same_as":"order.open_count","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"open_orders":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.archive","description":"Take a CMS page off the live site into the trash, recoverably. The page is snapshotted, unpublished and hidden from every listing and public route; page.restore brings it back (unpublished). A public change when the page was live — the owner's visitors stop seeing it.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":"page.restore","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/archive","http_method":"POST","dispatch_endpoint":null},{"name":"page.coming_soon","description":"Create an unpublished draft CMS page (website_pages) from the coming_soon template, with default title 'Coming Soon' and slug 'coming-soon'. Returns the new page.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","default":"Coming Soon"},"slug":{"type":"string","default":"coming-soon"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/coming-soon","http_method":"POST","dispatch_endpoint":null},{"name":"page.create","description":"Create a new CMS page (draft). Optional layout_json populates initial sections; otherwise the page comes out empty for an agent to fill via subsequent updates.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"slug":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"layout_json":{"type":"object","nullable":true},"page_type":{"type":"string","default":"website"},"template":{"type":"string","default":"default"},"site_id":{"type":"integer","minimum":1,"nullable":true},"is_landing_page":{"type":"boolean","default":false},"show_in_nav":{"type":"boolean","default":true},"ai_generated":{"type":"boolean","default":false},"ai_prompt":{"type":"string","nullable":true},"featured_image":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/create","http_method":"POST","dispatch_endpoint":null},{"name":"page.delete","description":"Move a CMS page to the trash. Reversible: the page is snapshotted and can be restored with page.restore. There is no permanent page deletion — this does exactly what page.archive does, but the name is held at R3 (owner approval). Prefer page.archive.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/delete","http_method":"POST","dispatch_endpoint":null},{"name":"page.discard_draft","description":"Throw away a page's unpublished draft. The live version is untouched.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/discard-draft","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"draft_discarded":{},"error":{},"page_id":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.drafts_list","description":"List every page with unpublished draft edits.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/drafts-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"drafts":{},"error":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.duplicate","description":"Duplicate an existing website page into a NEW unpublished draft with a fresh slug ('<slug>-copy'). The copy is never published automatically — edit it, then publish separately. Use for 'make a copy of that page'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to duplicate."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/duplicate","http_method":"POST","dispatch_endpoint":null},{"name":"page.edit","description":"Edit a website page's metadata + config: title, slug, description, featured image, page type, landing-page flag, and custom <head>/<body> injection (Professional+ tier). Layout / block content still goes through the visual canvas. Slug must remain unique within the company; collisions reject. Idempotent: passing the same values is a no-op.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to edit."},"title":{"type":"string","description":"New page title. Omit to leave unchanged.","minLength":1,"maxLength":500},"slug":{"type":"string","description":"New slug (lowercase alphanum + dashes). Omit to leave unchanged.","minLength":1,"maxLength":200},"description":{"type":"string","description":"New meta description. Omit to leave unchanged.","maxLength":5000},"featured_image":{"type":"string","description":"Featured/social-share image URL. Omit to leave unchanged."},"page_type":{"type":"string","description":"Page type: website, landing, blog, booking, product. Omit to leave unchanged."},"is_landing_page":{"type":"boolean","description":"Render without nav/footer (landing page). Omit to leave unchanged."},"custom_head":{"type":"string","description":"HTML injected into <head>. Professional+ tier. On the *.solidnumber.com address only <style> and Google Fonts links render (no <script> ever runs there — it shares the dashboard's session cookie); analytics/GTM/Hotjar scripts run only on a verified custom domain. The receipt says what will not run. Omit to leave unchanged.","maxLength":65536},"custom_body_start":{"type":"string","description":"HTML injected at start of <body>. Professional+ tier. Same host rule as custom_head: on *.solidnumber.com only <style> renders; scripts and embeds run only on a verified custom domain. Omit to leave unchanged.","maxLength":65536},"custom_body_end":{"type":"string","description":"HTML injected at end of <body>. Professional+ tier. Same host rule as custom_head: on *.solidnumber.com only <style> renders; scripts and embeds run only on a verified custom domain. Omit to leave unchanged.","maxLength":65536},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"reserved_slug","when":"The new slug is reserved by the platform.","override":null,"code_in_response":true},{"code":"slug_taken","when":"Another page already uses the new slug.","override":null,"code_in_response":true},{"code":"custom_code_rejected","when":"Custom code loads an undeclared host, embeds a form/iframe elsewhere, or is obfuscated.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/edit","http_method":"POST","dispatch_endpoint":null},{"name":"page.edit_content","description":"Edit a website page's BODY — the actual sections/blocks (layout_json), not just its title/meta (that's page_edit). Call get_block_schema first so the layout_json matches the block schema. Writes to a DRAFT by default (safe to preview); pass publish=true to push it live. This is how you rebuild what a page SAYS by talking.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id (from list_pages)."},"layout_json":{"type":"object","description":"The page body — sections/blocks matching get_block_schema."},"publish":{"type":"boolean","description":"False (default) writes a draft; true pushes live."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","layout_json"]},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/edit-content","http_method":"POST","dispatch_endpoint":null},{"name":"page.ensure","description":"Build the pages this company is missing, in the design it already has — its brand tokens, and the stylesheet of a brought design when there is one. Pages it can already generate from the KB are delegated to the website generator rather than duplicated. Everything created is OUT of the menu (show_in_nav=false): it exists and is addressable, and being in the menu is a separate choice. On a one-page site an anchorable requirement is added as a SECTION with an #anchor instead, and the result says which shape each item took. `slugs` narrows it, and also accepts a slug that is not required ('warranty'). dry_run plans only.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slugs":{"type":"array","items":{"type":"string"},"nullable":true},"publish":{"type":"boolean","default":true},"dry_run":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/ensure","http_method":"POST","dispatch_endpoint":null},{"name":"page.get","description":"Fetch a single CMS page by id with its full layout_json.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"page":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.get_by_slug","description":"Fetch one CMS page (website_pages) by its URL slug within this tenant, including pages in the trash. Returns the full page record, or an error if no page has that slug.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1}},"required":["slug"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/get-by-slug","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"page":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.history","description":"List saved versions of a website page (newest first) so you can see what changed and pick a version to roll back to. Pass a page slug for one page, or omit it for recent versions across all pages. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug (from list_pages). Omit for all pages."},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Max rows. Default 50."}}},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/history","http_method":"POST","dispatch_endpoint":null},{"name":"page.inventory","description":"Which pages this company MUST have, which it has, and which are missing — derived from its tier, enabled features and industry (booking on → a booking page; payments on → checkout + thank-you; always privacy, terms and a way to make contact). Also reports the SHAPE of the site: a one-page site with #anchors, or a set of pages. Pass `want` (e.g. 'financing') and it answers whether 'add that page' means a SECTION on the one-pager or a real page, and where.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"want":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/inventory","http_method":"POST","dispatch_endpoint":null},{"name":"page.list","description":"List CMS website pages for the tenant. Filter by page_type, site_id, or published_only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"published_only":{"type":"boolean","default":false},"page_type":{"type":"string","nullable":true},"site_id":{"type":"integer","minimum":1,"nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50},"skip":{"type":"integer","minimum":0,"default":0}},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"limit":{},"pages":{},"skip":{},"success":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.preview_url","description":"Get a signed, shareable link that shows a page INCLUDING its unpublished draft — see a change before publishing it. Returns has_draft so you can tell a real preview from a link to what is already live.","shape":"receipt","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"ttl_hours":{"type":"integer","minimum":1,"maximum":168,"default":24}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/preview-url","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"api_url":{},"expires_at":{},"has_draft":{},"page_id":{},"preview_url":{},"status":{},"unavailable":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.publish","description":"Publish a CMS page (is_published=True) — this is the step that makes it public. Triggers the SEO-MCP refresh. A page a Nest import built is refused if the conversion scores below the fidelity floor against the site it was cloned from; accept_fidelity takes it anyway, deliberately.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"accept_fidelity":{"type":"integer","nullable":true,"description":"Publish a lower-fidelity clone knowingly."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":"page.unpublish","refuses_when":[{"code":"publish_requires_subscription","when":"The company has no active subscription.","override":null,"code_in_response":true},{"code":"fidelity_below_threshold","when":"The page came from a Nest import scored below the fidelity bar (hand-built and unscored pages are never blocked).","override":"accept_fidelity","code_in_response":true},{"code":"blocked_by_guardrails","when":"Publishing is locked for the site.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/publish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"fidelity":{},"next":{},"reason":{},"success":{},"violations":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.publish_all_drafts","description":"Publish every unpublished draft page for the tenant in one atomic batch.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/publish-all-drafts","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"page_ids":{},"promoted":{},"published_count":{},"reason":{},"skipped_page_ids":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.publish_everything","description":"Promote EVERY pending page draft in this company to live in one shot. Each page goes through the same publish pipeline as a single publish (paywall, guardrails, snapshot, draft-promotion). Guardrail-locked pages are skipped, not force-published.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/publish-everything","http_method":"POST","dispatch_endpoint":null},{"name":"page.restore","description":"Bring a trashed/archived CMS page back. It returns UNPUBLISHED — restoring never silently re-exposes a page to the public; publish it again with page.publish. Answers page_not_trashed for a page that is not in the trash.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":"page.archive","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/restore","http_method":"POST","dispatch_endpoint":null},{"name":"page.revert","description":"Put a page back the way it was — the WHOLE page, or ONE section with every other edit kept. Defaults to one step back; `steps` goes further and `to_version` jumps to a version from page.history. `preview=true` reports exactly what would change and writes nothing. A revert is itself snapshotted, so it can be reverted in turn, and on a published page it stages a draft rather than changing the live site.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1,"nullable":true},"slug":{"type":"string","nullable":true},"section_id":{"type":"string","nullable":true},"steps":{"type":"integer","minimum":1,"default":1},"to_version":{"type":"integer","minimum":1,"nullable":true},"preview":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/revert","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"available":{},"changed":{},"error":{},"fields":{},"fields_restored":{},"from_version":{},"layout_changes":{},"message":{},"note":{},"page_id":{},"position":{},"preview":{},"reason":{},"scope":{},"section":{},"sections_in_version":{},"slug":{},"success":{},"target":{},"warnings":{},"was_removed":{},"went_to_draft":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.rollback","description":"Roll a website page back to a previous version (from page_history). The current state is snapshotted first, so a rollback is itself reversible. Restores the page's title, body, and description.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug (from list_pages / page_history)."},"version":{"type":"integer","description":"Version number to restore (from page_history)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","version"]},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/rollback","http_method":"POST","dispatch_endpoint":null},{"name":"page.schema","description":"Return the block-schema catalog (block types + required fields). Agents call this before emitting layout_json.sections.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/schema","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"block_count":{},"block_schema":{},"block_types":{},"motion_schema":{},"note":{},"prop_notes":{},"success":{},"type_aliases":{},"universal_optional_props":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.section.add","description":"Add one block to a page without rewriting the whole layout. Returns the new section_id. `props` go at the TOP LEVEL of the section, using the prop names page.schema reports for that block type — nesting them under a 'props' key is the mistake that makes a block render its default silently. Any prop the block does not accept comes back in ignored_unknown_props rather than being swallowed.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer"},"type":{"type":"string"},"props":{"type":"object","nullable":true},"position":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","type"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/section.add","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"accepted_aliases":{},"error":{},"hint":{},"ignored_unknown_props":{},"index":{},"known_props":{},"page_id":{},"reason":{},"section_id":{},"success":{},"type":{},"valid_types":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.section.list","description":"List a page's sections as (index, id, type). These ids are the addresses page.section.update / reorder / remove take. Call this before editing.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer"}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/section.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"error":{},"message":{},"ok":{},"page_id":{},"reason":{},"sections":{},"source":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.section.remove","description":"Delete one section by id. Reversible — the prior layout is snapshotted to page history first, so page.rollback can bring it back.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer"},"section_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","section_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/section.remove","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"page_id":{},"remaining":{},"removed":{},"sections":{},"success":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.section.reorder","description":"Move one section to an absolute index; the rest keep their order.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer"},"section_id":{"type":"string"},"position":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","position","section_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/section.reorder","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"from_index":{},"page_id":{},"section_id":{},"sections":{},"success":{},"to_index":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.section.update","description":"Merge props into ONE section by id, leaving every other section untouched. Unknown props are reported, not silently kept.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer"},"section_id":{"type":"string"},"props":{"type":"object","nullable":true},"type":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id","section_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/section.update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"ignored_unknown_props":{},"index":{},"page_id":{},"section_id":{},"sections":{},"success":{},"type":{},"version":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.set_nav_visibility","description":"Show or hide ONE page in the tenant site's menu — 'hide the financing page' / 'put it back' in a single call, by page_id or slug. This is NOT unpublishing: the page stays live and addressable at its URL, it just leaves the menu. A tenant with a curated nav_links has that list kept in step, so showing a page it does not name actually makes it appear.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1,"nullable":true},"slug":{"type":"string","minLength":1,"nullable":true},"show":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/set-nav-visibility","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"changed":{},"error":{},"looked_for":{},"menu":{},"message":{},"nav_links_sync":{},"page":{},"success":{},"was":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.unpublish","description":"Unpublish a CMS page (is_published=False). The page is preserved as a draft.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":"page.publish","refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/unpublish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"page":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page.update","description":"Update an existing CMS page. Layout changes are auto-versioned (previous layout_json snapshot is preserved). Only the fields you pass are touched. custom_head / custom_body_start / custom_body_end inject raw HTML into the rendered page — a pixel, a schema block, a rule that hides something — and are Professional+ and scanned before they are stored; they are site chrome, so they go live rather than staging as a draft.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"layout_json":{"type":"object","nullable":true},"template":{"type":"string","nullable":true},"featured_image":{"type":"string","nullable":true},"page_type":{"type":"string","nullable":true},"custom_head":{"type":"string","nullable":true},"custom_body_start":{"type":"string","nullable":true},"custom_body_end":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"70","noun":"page","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/page/update","http_method":"POST","dispatch_endpoint":null},{"name":"page_create","description":"Create a new website page with an empty layout. Slug must be lowercase alphanumeric + dashes, unique within this company's site. Use this when the user wants to start a new page from scratch. For AI-generated content (Ace / Alex agents writing the page for them), they should call the cms/pages/ai/generate endpoint separately.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug (e.g. 'about-us', 'services-dental'). Lowercase, alphanumeric + dashes. Max 200 chars.","minLength":1,"maxLength":200},"title":{"type":"string","description":"Page title (shown in browser tab and SEO). 1–500 chars.","minLength":1,"maxLength":500},"description":{"type":"string","description":"Optional page description / meta-description. Max 5000 chars.","maxLength":5000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","title"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"page_id":{},"slug":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_delete","description":"Move a website page to the trash (soft-delete). The page drops off the live site and every listing, but its full history is preserved and it can be restored later. Reversible — this never hard-deletes.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to trash."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.delete","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"page_id":{},"trashed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_discard_draft","description":"Throw away a page's pending draft (unpublished edits). The LIVE version is untouched — only the draft shadow is cleared. Use when the user says 'discard my changes' or 'revert the draft'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id whose draft to discard."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.discard_draft","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"draft_discarded":{},"ok":{},"page_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_duplicate","description":"Duplicate an existing website page into a NEW unpublished draft with a fresh slug ('<slug>-copy'). The copy is never published automatically — edit it, then publish separately. Use for 'make a copy of that page'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to duplicate."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.duplicate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"is_published":{},"ok":{},"page_id":{},"slug":{},"source_page_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_edit","description":"Edit a website page's metadata + config: title, slug, description, featured image, page type, landing-page flag, and custom <head>/<body> injection (Professional+ tier). Layout / block content still goes through the visual canvas. Slug must remain unique within the company; collisions reject. Idempotent: passing the same values is a no-op.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to edit."},"title":{"type":"string","description":"New page title. Omit to leave unchanged.","minLength":1,"maxLength":500},"slug":{"type":"string","description":"New slug (lowercase alphanum + dashes). Omit to leave unchanged.","minLength":1,"maxLength":200},"description":{"type":"string","description":"New meta description. Omit to leave unchanged.","maxLength":5000},"featured_image":{"type":"string","description":"Featured/social-share image URL. Omit to leave unchanged."},"page_type":{"type":"string","description":"Page type: website, landing, blog, booking, product. Omit to leave unchanged."},"is_landing_page":{"type":"boolean","description":"Render without nav/footer (landing page). Omit to leave unchanged."},"custom_head":{"type":"string","description":"HTML injected into <head>. Professional+ tier. On the *.solidnumber.com address only <style> and Google Fonts links render (no <script> ever runs there — it shares the dashboard's session cookie); analytics/GTM/Hotjar scripts run only on a verified custom domain. The receipt says what will not run. Omit to leave unchanged.","maxLength":65536},"custom_body_start":{"type":"string","description":"HTML injected at start of <body>. Professional+ tier. Same host rule as custom_head: on *.solidnumber.com only <style> renders; scripts and embeds run only on a verified custom domain. Omit to leave unchanged.","maxLength":65536},"custom_body_end":{"type":"string","description":"HTML injected at end of <body>. Professional+ tier. Same host rule as custom_head: on *.solidnumber.com only <style> renders; scripts and embeds run only on a verified custom domain. Omit to leave unchanged.","maxLength":65536},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.edit","status":"active","inverse":null,"refuses_when":[{"code":"reserved_slug","when":"The new slug is reserved by the platform.","override":null,"code_in_response":true},{"code":"slug_taken","when":"Another page already uses the new slug.","override":null,"code_in_response":true},{"code":"custom_code_rejected","when":"Custom code loads an undeclared host, embeds a form/iframe elsewhere, or is obfuscated.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"page_history","description":"List saved versions of a website page (newest first) so you can see what changed and pick a version to roll back to. Pass a page slug for one page, or omit it for recent versions across all pages. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug (from list_pages). Omit for all pages."},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Max rows. Default 50."}}},"required_scope":"pages:read","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.history","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"found":{},"slug":{},"versions":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_preview_url","description":"Create a shareable, expiring PREVIEW link of the current site — a snapshot of all pages (and KB). Nothing goes live; it's a safe link to review or send to someone. Creates the link, so it is confirmed first; anyone holding the link can open it, and it shows only knowledge-base entries marked public.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200,"description":"Optional label for the preview."},"ttl_hours":{"type":"integer","minimum":1,"maximum":720,"description":"Hours until the link expires. Default 72."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.preview_url","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"expires_at":{},"ok":{},"page_count":{},"preflight":{},"preview_url":{},"title":{},"ttl_hours":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_publish","description":"Publish an existing website page (sets is_published=true and published_at=NOW). Idempotent — re-publishing an already-published page is a no-op success.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to publish."},"accept_fidelity":{"type":"integer","minimum":0,"maximum":100,"description":"Only for a page cloned by Nest that was refused for fidelity: publish anyway at this score. A deliberate, recorded decision — never pass it unless the owner accepted the lower-fidelity copy."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.publish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"is_published":{},"ok":{},"page_id":{},"promoted_fields":{},"slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_publish_all","description":"Promote EVERY pending page draft in this company to live in one shot. Each page goes through the same publish pipeline as a single publish (paywall, guardrails, snapshot, draft-promotion). Guardrail-locked pages are skipped, not force-published.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.publish_everything","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"page_ids":{},"promoted":{},"skipped_page_ids":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_rollback","description":"Roll a website page back to a previous version (from page_history). The current state is snapshotted first, so a rollback is itself reversible. Restores the page's title, body, and description.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"Page slug (from list_pages / page_history)."},"version":{"type":"integer","description":"Version number to restore (from page_history)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug","version"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.rollback","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"new_version":{},"ok":{},"restored_version":{},"slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"page_unpublish","description":"Take a published page offline (sets is_published=false). The page row is preserved — re-publishing reactivates it. Use when the user says 'pull that page down' or 'hide that page'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"page_id":{"type":"integer","description":"website_pages.id to unpublish."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["page_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"70","noun":"page","location":"svc.api","same_as":"page.unpublish","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"is_published":{},"ok":{},"page_id":{},"slug":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"partial_capture","description":"Capture a portion of a prior authorization. Some processors (Stripe, Adyen, Braintree) support auth-then-partial-capture; others reject. Returns op_not_supported_by_adapter if the company's processor lacks the method. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string","description":"Authorization id"},"amount_cents":{"type":"integer","minimum":1},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id","amount_cents"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"80","noun":"capture","location":"svc.api","same_as":"capture.partial","status":"active","inverse":null,"refuses_when":[{"code":"processor_not_connected","when":"The named processor is not connected.","override":null,"code_in_response":true},{"code":"no_processor_connected","when":"No payment processor is connected.","override":null,"code_in_response":true},{"code":"adapter_not_connected","when":"The processor has no credentials for this environment, or a test processor is on a live connection.","override":null,"code_in_response":true},{"code":"op_not_supported_by_adapter","when":"The connected processor's adapter cannot partially capture.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"payment.charge","description":"Process a payment charge through the company's default payment processor. Universal — uses whatever processor is connected.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1},"currency":{"type":"string","default":"usd"},"source":{"type":"object","nullable":true},"description":{"type":"string","nullable":true},"idempotency_key":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount_cents"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"530","noun":"payment","acts_on":{"noun":"payment","address":"530","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/charge","http_method":"POST","dispatch_endpoint":null},{"name":"payment.check_on_file","description":"May this stored card be charged, and what must the charge carry? Returns the initiation type, the mandate reference and the reason, or a refusal naming what is missing — an expired card or an absent mandate. Moves no money.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"payment_method_id":{"type":"string","minLength":1},"amount_cents":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true},"cardholder_present":{"type":"boolean","nullable":true}},"required":["payment_method_id","amount_cents"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"532","noun":"card_on_file","acts_on":{"noun":"card_on_file","address":"532","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor_token","when":"The saved payment method has no processor token.","override":null,"code_in_response":false},{"code":"card_expired","when":"The saved card has expired.","override":null,"code_in_response":false},{"code":"no_mandate","when":"A cardholder-not-present charge with no stored-credential mandate on file.","override":"cardholder_present","code_in_response":false}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/check-on-file","http_method":"POST","dispatch_endpoint":null},{"name":"payment.explain_charge_failure","description":"Explain why a charge failed, for a row in the transactions table by numeric transaction_id: classified failure reason, AI fraud flag, risk score, and auth-without-capture. Returns factors and a narrative.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"integer","minimum":1}},"required":["transaction_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"530","noun":"payment","acts_on":{"noun":"payment","address":"530","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/explain-charge-failure","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"factors":{},"narrative":{},"success":{},"transaction":{},"warnings":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payment.full_history","description":"Aggregate payment timeline for a CRM contact: charges + refunds + outstanding balance, in one call. `customer_id` is a crm_contacts id. Disputes and stored cards are reported as unavailable, never as empty.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"customer_id":{"type":"integer","minimum":1},"limit":{"type":"integer","minimum":1,"maximum":500,"default":50},"include_disputes":{"type":"boolean","default":true},"include_payment_methods":{"type":"boolean","default":true}},"required":["customer_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"530","noun":"payment","acts_on":{"noun":"payment","address":"530","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/full-history","http_method":"POST","dispatch_endpoint":null},{"name":"payment.methods_on_file","description":"Cards stored for this merchant — brand and last four only — and which of them can actually be re-run. A card with a token but no mandate is on file and NOT re-runnable, and the two look identical until asked.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"532","noun":"card_on_file","acts_on":{"noun":"card_on_file","address":"532","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/methods-on-file","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"methods":{},"note":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payment.refund","description":"Process a payment refund through the company's default processor.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string","minLength":1},"amount_cents":{"type":"integer","nullable":true},"idempotency_key":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"531","noun":"refund","acts_on":{"noun":"refund","address":"531","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/refund","http_method":"POST","dispatch_endpoint":null},{"name":"payment.status","description":"Look up the status of a payment link by its link_id (the id returned when the link was created). Returns whether it has been paid, the amount, and the transaction id. Read-only. Returns found=false if no such link exists for this company — do not fabricate a status.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"link_id":{"type":"string","description":"The payment link's link_id."}},"required":["link_id"]},"required_scope":"payments:read","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/status","http_method":"POST","dispatch_endpoint":null},{"name":"payment.stored_credential_reasons","description":"The reasons a stored card may be charged — recurring, installment, unscheduled, resubmission, delayed charge, no-show, reauthorization — and what each means. The reason is what a merchant points at if the charge is disputed.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"532","noun":"card_on_file","acts_on":{"noun":"card_on_file","address":"532","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/stored-credential-reasons","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reasons":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payment.void","description":"Void an unsettled authorization (cancel before it captures). Cheaper than a refund when the charge hasn't settled yet. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id"]},"required_scope":"payments:write","transport":"http","coordinate":"530","noun":"payment","acts_on":{"noun":"payment","address":"530","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment/void","http_method":"POST","dispatch_endpoint":null},{"name":"payment_link.create","description":"Create a hosted payment link the customer can click to pay. Customer enters their card on the processor's hosted page — ADA never sees or stores the card. Preferred pattern over direct charges. Requires admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1},"currency":{"type":"string","default":"USD"},"description":{"type":"string","maxLength":200},"contact_id":{"type":"integer","description":"Optional: CRM contact id to attach to the link."},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount_cents"]},"required_scope":"payments:write","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment_link/create","http_method":"POST","dispatch_endpoint":null},{"name":"payment_link.send","description":"Create a payment link AND send it to a contact via SMS or email. Wraps payment_link_create + send. Customer authorizes the charge by entering their card on the processor's hosted page — ADA never touches the card. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer"},"amount_cents":{"type":"integer","minimum":1},"channel":{"type":"string","enum":["sms","email"]},"description":{"type":"string","maxLength":200},"currency":{"type":"string","default":"USD"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","amount_cents"]},"required_scope":"payments:write","transport":"http","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payment_link/send","http_method":"POST","dispatch_endpoint":null},{"name":"payment_link_create","description":"Create a hosted payment link the customer can click to pay. Customer enters their card on the processor's hosted page — ADA never sees or stores the card. Preferred pattern over direct charges. Requires admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1},"currency":{"type":"string","default":"USD"},"description":{"type":"string","maxLength":200},"contact_id":{"type":"integer","description":"Optional: CRM contact id to attach to the link."},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount_cents"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"payment_link.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"payment_link_send","description":"Create a payment link AND send it to a contact via SMS or email. Wraps payment_link_create + send. Customer authorizes the charge by entering their card on the processor's hosted page — ADA never touches the card. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer"},"amount_cents":{"type":"integer","minimum":1},"channel":{"type":"string","enum":["sms","email"]},"description":{"type":"string","maxLength":200},"currency":{"type":"string","default":"USD"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","amount_cents"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"payment_link.send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount_cents":{},"amount_display":{},"channel":{},"contact":{},"contact_id":{},"error":{},"preflight":{},"processor":{},"stage":{},"status":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payment_status_get","description":"Look up the status of a payment link by its link_id (the id returned when the link was created). Returns whether it has been paid, the amount, and the transaction id. Read-only. Returns found=false if no such link exists for this company — do not fabricate a status.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"link_id":{"type":"string","description":"The payment link's link_id."}},"required":["link_id"]},"required_scope":"payments:read","transport":"dispatch","coordinate":"533","noun":"payment_link","acts_on":{"noun":"payment_link","address":"533","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"payment.status","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"amount":{},"currency":{},"description":{},"found":{},"link_id":{},"note":{},"ok":{},"paid":{},"paid_at":{},"status":{},"transaction_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payment_void","description":"Void an unsettled authorization (cancel before it captures). Cheaper than a refund when the charge hasn't settled yet. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"530","noun":"payment","acts_on":{"noun":"payment","address":"530","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"payment.void","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"payments.chargebacks","description":"Payments — disputes the processor is currently holding against this merchant, for a date range. Universal across processors: asks whichever adapter the merchant connected. ⛔ Returns an explicit 'unsupported' when the connected processor cannot list disputes — that is NOT the same as having none, and must never be rendered as zero chargebacks.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string"},"until":{"type":"string"}},"required":["since","until"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"542","noun":"dispute","acts_on":{"noun":"dispute","address":"542","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor_connected","when":"No payment processor is connected.","override":null,"code_in_response":true},{"code":"processor_unavailable","when":"The processor could not be reached or configured.","override":null,"code_in_response":true},{"code":"chargebacks_unsupported","when":"The connected processor's adapter cannot list disputes — never read this as zero chargebacks.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payments/chargebacks","http_method":"POST","dispatch_endpoint":null},{"name":"payments.deposits","description":"Payments — what the processor actually paid into the merchant's bank for a date range, net of fees, holds, reserves, refunds and chargebacks. A deposit is NOT a sale, and the gap between the two is what a merchant reconciles. ⛔ Returns an explicit 'unsupported' when the connected processor cannot list payouts — never an empty list, which would read as 'nothing landed'.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string"},"until":{"type":"string"}},"required":["since","until"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"541","noun":"settlement","acts_on":{"noun":"settlement","address":"541","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor_connected","when":"No payment processor is connected.","override":null,"code_in_response":true},{"code":"processor_unavailable","when":"The processor could not be reached or configured.","override":null,"code_in_response":true},{"code":"deposits_unsupported","when":"The connected processor's adapter cannot list payouts — never read this as nothing deposited.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payments/deposits","http_method":"POST","dispatch_endpoint":null},{"name":"payments.preview_refund_impact","description":"Project the impact of refunding a transaction WITHOUT executing it.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"integer","minimum":1},"refund_amount_cents":{"type":"integer","minimum":1,"nullable":true}},"required":["transaction_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"531","noun":"refund","acts_on":{"noun":"refund","address":"531","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/payments/preview-refund-impact","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"prior_refund_total_cents":{},"prior_refunds":{},"projection":{},"reasons":{},"success":{},"transaction":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"payout_run","description":"Trigger a payout from the processor's balance to the merchant's bank. Omit amount_cents for full available balance. IRREVERSIBLE — owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1},"currency":{"type":"string","default":"USD"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"payments:write","transport":"dispatch","coordinate":"541","noun":"settlement","acts_on":{"noun":"settlement","address":"541","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":"settlement.run_payout","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"performance.alerts.list","description":"List this company's performance alerts (performance_alerts), newest first; filters severity and status (default new), limit. Platform-wide alerts are not shown. Returns alerts with thresholds and a critical_count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"severity":{"type":"string","description":"Filter by severity ('low', 'medium', 'high', 'critical')"},"status":{"type":"string","description":"Filter by status (default: 'new')"},"limit":{"type":"integer","description":"Maximum number of alerts to return"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"performance","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/performance/alerts.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"alerts":{},"count":{},"critical_count":{},"error":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"performance.trace.get","description":"Get detailed information for a specific trace","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"trace_id":{"type":"string","description":"The trace ID to retrieve"}},"required":["trace_id"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"performance","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/performance/trace.get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"trace":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"performance.trace.live","description":"Get live request traces from in-memory buffer","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of traces to return (default: 100)"},"slow_only":{"type":"boolean","description":"Only return slow requests (>1s) (default: False)"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"performance","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/performance/trace.live","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"error":{},"slow_count":{},"success":{},"traces":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.call_queue","description":"Callers who are connected but NOT yet answered, oldest first, each with how long they have been waiting. A queue is not the active-call list: an active call is being handled, a queued caller is waiting, and the wait is the number that matters. Returns the longest current wait.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/call-queue","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"longest_wait_seconds":{},"waiting":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.call_trace","description":"Every engine event inside one call, in order — what actually happened, as opposed to what the transcript says. Proves ownership of the call under company_id BEFORE reading its events, so a call id belonging to another tenant is indistinguishable from one that does not exist.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer"}},"required":["call_id"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/call-trace","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"call":{},"deals_created":{},"error":{},"event_count":{},"events":{},"verb_count":{},"verbs_run":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.caller_id_status","description":"Ask Twilio whether caller-ID verification has completed for a number. Twilio does not call back when it does, so the status is only true once we look.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/caller-id-status","http_method":"POST","dispatch_endpoint":null},{"name":"phone.caller_id_verify","description":"Start Twilio caller-ID verification so outbound calls present the CUSTOMER'S own number instead of ours — the number their customers recognise and don't screen. Twilio rings that number and waits for the six-digit code this returns; read it to whoever is standing at the phone.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/caller-id-verify","http_method":"POST","dispatch_endpoint":null},{"name":"phone.daily_report","description":"One day on the phone in plain counts: total, answered, MISSED (ended without ever being answered — the number no other surface reported), voicemail, escalated, inbound/outbound, average duration, total talk time, breakdowns by outcome and sentiment, and by_hour — 24 buckets, always all 24, because an empty hour is a real gap and a missing bar silently compresses the axis. Phone traffic is bursty; the shape of the day is the insight a total hides. Defaults to today; pass day as YYYY-MM-DD.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"day":{"type":"string","nullable":true,"description":"YYYY-MM-DD, default today (UTC)"}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"621","noun":"call_report","acts_on":{"noun":"call_report","address":"621","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/daily-report","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"answered":{},"avg_duration_seconds":{},"busiest_hour":{},"by_hour":{},"by_outcome":{},"by_sentiment":{},"day":{},"escalated":{},"inbound":{},"missed":{},"outbound":{},"talk_time_seconds":{},"total_calls":{},"voicemail":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.dropoff_report","description":"Where calls end and how. Grouped two ways because they answer different questions: by_step is WHERE in the conversation callers leave, by_reason is HOW the call ended. The headline is no_outcome — answered calls that produced nothing — with examples worth listening to.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":7}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"621","noun":"call_report","acts_on":{"noun":"call_report","address":"621","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/dropoff-report","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"answered":{},"by_reason":{},"by_step":{},"calls_considered":{},"examples":{},"no_outcome":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.escalations","description":"Calls the AI handed to a person, and why. Keeps two signals apart: transferred_to is a call that REACHED a human, escalation_trigger is a call that asked to. never_reached_a_person counts the ones that asked and did not — the interesting failure, not something to average into a rate.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":90,"default":7}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"621","noun":"call_report","acts_on":{"noun":"call_report","address":"621","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/escalations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"by_reason":{},"count":{},"escalations":{},"never_reached_a_person":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.external_add","description":"Record a number the customer already owns so we can show the right setup steps and prove calls arrive. Nothing about their number, carrier or billing changes. Starts UNPROVEN — it becomes connected on its own the first time a real forwarded call comes through.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone_number":{"type":"string","description":"the customer's own number, E.164"},"label":{"type":"string","nullable":true,"description":"e.g. \"Front desk\", \"Ogden clinic\""},"carrier":{"type":"string","nullable":true,"description":"who they buy phone service from — decides which instructions we show"},"connection_method":{"type":"string","enum":["forward","port","sip"],"default":"forward"},"line_id":{"type":"integer","nullable":true,"description":"which of our lines this number reaches"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["phone_number"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/external-add","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"external_number_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.external_instructions","description":"The exact forwarding steps to hand this customer, shaped by their carrier: star codes for a traditional line (*92 no-answer, *90 busy, *72 all calls, and the codes to cancel), or the portal path for a VoIP carrier where star codes do nothing. Names the destination number literally. Overflow is recommended over full takeover.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/external-instructions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connection_status":{},"destination":{},"error":{},"external_number_id":{},"phone_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.external_list","description":"Every number the CUSTOMER already owns (their landline, front desk, second location) and whether it truly reaches us: connection method, which of our lines it feeds, whether a real call has ever arrived over it, whether their carrier strips the caller's number, caller-ID and port state, plus the forwarding steps for their specific carrier. `is_connected` is PROOF from an observed call, never a setting.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/external-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"external_numbers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.external_remove","description":"Stop tracking a number the customer owns. Deletes our record only — no effect on their carrier, their forwarding, or the number itself.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/external-remove","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"note":{},"phone_number":{},"removed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.external_update","description":"Edit a recorded number's label, carrier, connection method or destination line. Connection state and caller-ID state are deliberately NOT settable — they are evidence from observed calls and from Twilio, not preferences.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"label":{"type":"string","nullable":true},"carrier":{"type":"string","nullable":true},"connection_method":{"type":"string","enum":["forward","port","sip"],"nullable":true},"line_id":{"type":"integer","nullable":true},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/external-update","http_method":"POST","dispatch_endpoint":null},{"name":"phone.port_progress","description":"Record what the carrier came back with: a firm cutover date (FOC), a rejection reason kept verbatim, or the completed move. Progress arrives out of band — an email, a console notice, a phone call — so it is an explicit write, never inferred from elapsed time. Completing a port also makes the number presentable on outbound without any validation call, because we then own it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"status":{"type":"string","enum":["loa_pending","submitted","scheduled","completed","rejected","cancelled"]},"foc_date":{"type":"string","nullable":true,"description":"ISO 8601 cutover date the carrier committed to"},"rejection_reason":{"type":"string","nullable":true,"description":"verbatim from the carrier"},"reference":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id","status"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/port-progress","http_method":"POST","dispatch_endpoint":null},{"name":"phone.port_start","description":"Record the authorization details for moving the customer's number onto our account. Files NOTHING with any carrier — collecting these and getting them right IS the difficulty of a port, so filing is a separate deliberate act (phone.port_submit). Returns what is still missing. The billing telephone number is often NOT the number being moved.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"account_name":{"type":"string","nullable":true,"description":"business name exactly as on the phone bill"},"account_number":{"type":"string","nullable":true},"service_address":{"type":"string","nullable":true,"description":"service address on the account, not a PO box"},"billing_number":{"type":"string","nullable":true,"description":"BTN — often NOT the number being moved"},"loa_signed_by":{"type":"string","nullable":true,"description":"person authorised on the account"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/port-start","http_method":"POST","dispatch_endpoint":null},{"name":"phone.port_status","description":"Where a number's port stands (none | loa_pending | submitted | scheduled | completed | rejected | cancelled), the firm cutover date (FOC) if the carrier gave one, any rejection verbatim, and which account details are still missing before it can be filed — each with a plain-words prompt.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/port-status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"external_number_id":{},"phone_number":{},"port_foc_date":{},"port_reference":{},"port_rejection_reason":{},"port_status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone.port_submit","description":"File the port request with the carrier. Refuses on incomplete details and NEVER reports a success it cannot evidence — if filing fails the record does not advance and the number keeps working exactly as it does today. A port believed filed and not filed is discovered only when the customer asks why their number never moved.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"external_number_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["external_number_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"601","noun":"external_number","acts_on":{"noun":"external_number","address":"601","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"incomplete","when":"A required LOA field is missing; the response lists them.","override":null,"code_in_response":true},{"code":"already_in_flight","when":"The port is already submitted or scheduled.","override":null,"code_in_response":true},{"code":"twilio_unconfigured","when":"The platform's carrier credentials are not set; nothing is filed.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/port-submit","http_method":"POST","dispatch_endpoint":null},{"name":"phone.pricing","description":"Customer-facing phone pricing from the platform's single source: number rental (local/toll-free monthly), voice plan prices + included minutes, and call-transcription per-minute price. No wholesale costs, no markup — safe to quote to the customer directly.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"690","noun":"phone_charges","acts_on":{"noun":"phone_charges","address":"690","domain":"Solid# comms charges","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone/pricing","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"plans":{},"rental":{},"transcription":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"phone_line.provision","description":"Buy and provision a phone number for this company, with an owner (company front door / a user's shared line / an agent's line). Starts a MONTHLY rental — spends money. Returns the new line id + routing mode.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone_number":{"type":"string","description":"E.164 number to buy, e.g. +14155551234."},"number_type":{"type":"string","enum":["local","toll_free","short_code"],"description":"Default local."},"owner_type":{"type":"string","enum":["company","user","agent"],"description":"Who owns the line. Default company."},"agent_id":{"type":"integer","description":"Required if owner_type=agent."},"make_default":{"type":"boolean","description":"Make this the default outbound line."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["phone_number"]},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone_line/provision","http_method":"POST","dispatch_endpoint":null},{"name":"phone_line.release","description":"Release a phone line — stops the monthly rental (soft delete). Does NOT permanently release the number at the carrier (that stays a dashboard action). Reversible until the next billing run.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","description":"Phone line id to release."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id"]},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone_line/release","http_method":"POST","dispatch_endpoint":null},{"name":"phone_line.set_routing_mode","description":"Set who answers a phone line: 'ring' (human first, AI backs up) · 'ask' (live decision) · 'ai' (AI answers) · 'off' (human only). ring/ask require a user assigned to the line.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","description":"Phone line id (from call_flow_get / switchboard)."},"routing_mode":{"type":"string","enum":["ring","ask","ai","off"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","routing_mode"]},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/phone_line/set-routing-mode","http_method":"POST","dispatch_endpoint":null},{"name":"phone_number_provision","description":"Buy and provision a phone number for this company, with an owner (company front door / a user's shared line / an agent's line). Starts a MONTHLY rental — spends money. Returns the new line id + routing mode.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone_number":{"type":"string","description":"E.164 number to buy, e.g. +14155551234."},"number_type":{"type":"string","enum":["local","toll_free","short_code"],"description":"Default local."},"owner_type":{"type":"string","enum":["company","user","agent"],"description":"Who owns the line. Default company."},"agent_id":{"type":"integer","description":"Required if owner_type=agent."},"make_default":{"type":"boolean","description":"Make this the default outbound line."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["phone_number"]},"required_scope":"voice:write","transport":"dispatch","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"phone_line.provision","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"platform_invoice.list","description":"List the SUBSCRIPTION INVOICES Solid# has issued TO this company — what this company owes Solid#, not what its own customers owe it. For a company's own customer invoices use `invoice.list`. Filter by status (draft / open / paid / void / uncollectible). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","open","paid","void","uncollectible"],"description":"Filter by invoice status."},"limit":{"type":"integer","description":"Max invoices (default 20)."}}},"required_scope":null,"transport":"http","coordinate":"581","noun":"platform_invoice","acts_on":{"noun":"platform_invoice","address":"581","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/platform_invoice/list","http_method":"POST","dispatch_endpoint":null},{"name":"platform_invoice.mark_paid","description":"Solid# staff only: record that one of Solid#'s invoices to this company was paid outside the card on file (a check or ACH). Updates status='paid' and stamps paid_at=now; charges nothing. A company cannot mark its own bill from Solid# paid — its owner is told to contact Solid# billing. For the company's invoices to its own customers use invoice_record_payment.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"billing_invoices.id."},"note":{"type":"string","description":"Optional reconciliation note."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invoice_id"]},"required_scope":"ops:write","transport":"http","coordinate":"581","noun":"platform_invoice","acts_on":{"noun":"platform_invoice","address":"581","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_paid","when":"The billing invoice is already paid; answered as status already_paid, nothing changes.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/platform_invoice/mark-paid","http_method":"POST","dispatch_endpoint":null},{"name":"playbook.guide","description":"How this business runs, step by step: the everyday jobs of its kind of business (a new customer gets in touch, book, quote, do the job, get paid, ask for a review — or a shop's orders and stock) in the order they happen, each step naming the verb that does it, in this business's own words, plus the customer-journey stages its industry follows. Read it before acting for a business you do not know.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"15","noun":"playbook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/playbook/guide","http_method":"POST","dispatch_endpoint":null},{"name":"playbook.next_step","description":"The next step of a tenant's playbook, rendered in THEIR industry's words — a vet hears 'new patient' where a plumber hears 'lead'. Steps branch on the answer, and an action step returns the verb name for the agent to call. Read-only; safe every turn.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"playbook_id":{"type":"string"},"answered":{"type":"object","nullable":true},"current_id":{"type":"string","nullable":true},"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"}},"required":["playbook_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"15","noun":"playbook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/playbook/next-step","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"answered_count":{},"complete":{},"playbook_id":{},"status":{},"step":{},"summary":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"playbook.save","description":"Create or replace this tenant's playbook — their questions, their branching. A playbook they cannot change is our opinion of their business. Steps are parsed before storing: the runtime loader is forgiving so a live call never 500s, which means a malformed step would be silently flattened and only surface when a respondent heard it. Write {lead} / {appointment} / {customer} in prompts — they render into this industry's own words when spoken.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"steps":{"type":"array"},"playbook_id":{"type":"string","nullable":true},"kb_sub_code":{"type":"integer","nullable":true},"outcomes":{"type":"array","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title","steps"],"additionalProperties":true},"required_scope":"agents:write","transport":"http","coordinate":"15","noun":"playbook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid","when":"A step points at a step that does not exist, or an outcome band has no bounds; the summary lists them.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/playbook/save","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"playbook.suggest","description":"A starter playbook for this business, already in their industry's words — a vet's draft asks about the 'visit', a plumber's about the 'appointment'. Returns a DRAFT and saves nothing. This is what turns a blank form builder into one edit. Intents: intake, feedback, lead_qualify, onboarding.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intent":{"type":"string","default":"intake"},"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"15","noun":"playbook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/playbook/suggest","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"kb_sub_code":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"playbook.vocabulary","description":"The nouns this tenant's customers actually use — customer, lead, appointment, agent — in one of 5 languages. Asking a vet about 'the lead' is how a respondent learns the thing does not know their business.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"15","noun":"playbook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/playbook/vocabulary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"kb_sub_code":{},"lang":{},"status":{},"summary":{},"terms":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pos.activate_terminal","description":"POS — bring a countertop card terminal online through the merchant's connected processor. Returns ok=false with error terminal_unsupported when that processor cannot (none can yet) — no terminal was contacted. Not for Tap to Pay on a phone: use the payment-devices approval flow.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"terminal_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["terminal_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"536","noun":"terminal","acts_on":{"noun":"terminal","address":"536","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor_connected","when":"No payment processor is connected.","override":null,"code_in_response":true},{"code":"processor_unavailable","when":"The processor could not be reached or configured.","override":null,"code_in_response":true},{"code":"terminal_unsupported","when":"The connected processor's adapter cannot activate a countertop terminal.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pos/activate-terminal","http_method":"POST","dispatch_endpoint":null},{"name":"pos.charge_terminal","description":"POS — take a card-present payment on a countertop terminal through the merchant's connected processor. A payment happened ONLY if the response has ok=true; every other answer (terminal_unsupported, invalid_amount, no_processor_connected, processor_unavailable) means NO card was charged.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"terminal_id":{"type":"string"},"amount_cents":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["amount_cents","terminal_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"536","noun":"terminal","acts_on":{"noun":"terminal","address":"536","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor_connected","when":"No payment processor is connected; nothing is charged.","override":null,"code_in_response":true},{"code":"terminal_unsupported","when":"The connected processor's adapter cannot charge a countertop terminal; nothing is charged.","override":null,"code_in_response":true},{"code":"processor_unavailable","when":"The processor could not be reached or configured; nothing is charged.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pos/charge-terminal","http_method":"POST","dispatch_endpoint":null},{"name":"pos.tokenize_card","description":"POS — refuses by design: raw card data is never accepted through an agent (error card_data_refused; nothing is stored). Tokenize client-side with the processor's SDK and register the token via POST /api/v1/payments/methods.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"card_data":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["card_data"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"536","noun":"terminal","acts_on":{"noun":"terminal","address":"536","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"card_data_refused","when":"Always: raw card data is never accepted through an agent.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pos/tokenize-card","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"fix":{},"message":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"predict.deal_close","description":"Predict the probability that a CRM deal closes (won) vs lost.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"REQUIRED — the deal to predict for."}},"required":["deal_id"]},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/deal-close","http_method":"POST","dispatch_endpoint":null},{"name":"predict.no_show","description":"Predict the probability a customer no-shows an upcoming appointment.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"REQUIRED."}},"required":["appointment_id"]},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/no-show","http_method":"POST","dispatch_endpoint":null},{"name":"predict.payment_late","description":"Predict the probability an invoice is paid after its due_date.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"REQUIRED."}},"required":["invoice_id"]},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/payment-late","http_method":"POST","dispatch_endpoint":null},{"name":"predict.substrate.export","description":"Export this tenant's full substrate chain for offline audit.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since":{"type":"string","description":"optional ISO-8601 timestamp (action_taken_at >= since)"},"until":{"type":"string","description":"optional ISO-8601 timestamp (action_taken_at <= until)"},"limit":{"type":"integer","description":"optional cap (default 10000, max 50000)"}}},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/substrate.export","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"count":{},"error":{},"ok":{},"rows":{},"since":{},"until":{},"well_known_url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"predict.substrate.recent","description":"Read recent substrate rows for this tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"int (default 25, max 200)"},"agent":{"type":"string","description":"optional — filter by agent identifier (e.g. \"marcus\")"},"action_type":{"type":"string","description":"optional — filter by stable action key"},"only_with_outcome":{"type":"string","description":"bool — drop rows that haven't been resolved"}}},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/substrate.recent","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"rows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"predict.substrate.verify","description":"Verify the integrity of this tenant's substrate chain.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"optional cap on rows walked (default: all)"}}},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/substrate.verify","http_method":"POST","dispatch_endpoint":null},{"name":"predict.targets.list","description":"List Devon-discovered predict targets for this tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status_filter":{"type":"string","description":"Optional — \"proposed\" | \"approved\" | \"rejected\" | \"dormant\""}}},"required_scope":null,"transport":"http","coordinate":"19","noun":"predict","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/predict/targets.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"summary":{},"targets":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"predict_deal_close","description":"Predict the probability that a specific OPEN deal closes (is won). Uses TabPFN-v2 trained on this company's prior won/lost deals. Returns probability + confidence + driving features. If the company has too few closed deals, falls back to a heuristic with low confidence — caller MUST surface that lower confidence to the user.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"ID of the open deal to score."}},"required":["deal_id"]},"required_scope":null,"transport":"dispatch","coordinate":"19","noun":"predict","location":"svc.api","same_as":"predict.deal_close","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"predict_no_show","description":"Predict the probability that a scheduled appointment will be a no-show. Uses TabPFN-v2 trained on this company's prior appointment history. Returns probability + confidence + driving features. Honest about low-data situations.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","description":"ID of the scheduled appointment to score."}},"required":["appointment_id"]},"required_scope":null,"transport":"dispatch","coordinate":"19","noun":"predict","location":"svc.api","same_as":"predict.no_show","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"predict_payment_late","description":"Predict the probability that an open invoice will be paid late. Uses TabPFN-v2 trained on this company's prior invoice payment history. Returns probability + confidence + driving features. Use for cash-flow planning and proactive collections.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invoice_id":{"type":"integer","description":"ID of the open invoice to score."}},"required":["invoice_id"]},"required_scope":null,"transport":"dispatch","coordinate":"19","noun":"predict","location":"svc.api","same_as":"predict.payment_late","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"presence.set","description":"Set MY softphone presence (Phase 5, §2.2): available=true registers/heartbeats this client as a live ring leg for my line (surface: web/desktop/mobile); available=false deregisters it. As of 2026-09-09 the inbound answer path actually reads this and rings live clients. Optional `status` (available|busy|away) is the PERSON's intent as opposed to the device's reachability — omit it on a heartbeat, it is sticky. Strictly self-scoped — presence is per-user and a caller can only write their own.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"available":{"type":"boolean","default":true},"surface":{"type":"string","enum":["web","desktop","mobile"],"default":"web"},"status":{"type":"string","enum":["available","busy","away"],"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"680","noun":"presence","acts_on":{"noun":"presence","address":"680","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/presence/set","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"presence":{},"removed":{},"success":{},"ttl_seconds":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"presence.status","description":"My call settings — whether I am taking calls and where calls reach me. status available | busy | away applies on every device at once and holds with none registered (only 'available' rings). ring_app rings my signed-in web app; ring_cell + cell_number ring my cell too, which is how a call reaches me on the phone and what 'Take it' rings from the phone. Pass only what changes; pass nothing to read my settings. Self-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["available","busy","away"]},"cell_number":{"type":"string","description":"My cell, 10 digits or E.164. Empty string clears it."},"ring_cell":{"type":"boolean"},"ring_app":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"680","noun":"presence","acts_on":{"noun":"presence","address":"680","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/presence/status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"status":{},"success":{},"updated":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"presence.team","description":"Who is on the floor right now and who is actually taking calls — the workforce half of the phone console. phone.call_queue returns the callers WAITING; this returns the people they are waiting for. One entry per PERSON (not per device), carrying the surfaces they are reachable on, their status, and `rings` — the single answer to whether an inbound call would reach them right now. Read-only.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"680","noun":"presence","acts_on":{"noun":"presence","address":"680","domain":"Team","party":"tenant_staff","whose":"the business's dealings with its own people"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/presence/team","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"on_the_floor":{},"people":{},"success":{},"taking_calls":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.adjust_tip","description":"Pricing — add a tip after authorisation (tip-on-receipt) through the merchant's connected processor. Adapters that cannot adjust post-auth say so; the tip is then collected before the charge.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string"},"tip_cents":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id","tip_cents"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"534","noun":"tip","acts_on":{"noun":"tip","address":"534","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_processor","when":"No default payment processor is connected.","override":null,"code_in_response":true},{"code":"tip_adjust_unsupported","when":"The connected processor cannot adjust a tip after authorisation — collect it before the charge.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/adjust-tip","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.allowed_programs","description":"Pricing — which customer-facing fee programs the merchant's state allows, the surcharge cap, posting rules and network notice period. Legal facts are data, with sources.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"state":{"type":"string","description":"Two-letter US state; defaults to the merchant's business address"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/allowed-programs","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.compare_programs","description":"Pricing — one target the merchant wants to bank, and every way of getting there side by side: build it into the price (no programme, nothing to disclose, no cap), post the card price and discount for cash, post the cash price and show a card price, or add a surcharge. Shows what to post, what each tender pays, what the merchant actually nets, and exactly what each construction obliges them to do.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_net_cents":{"type":"integer","minimum":1},"cost_percent":{"type":"number","description":"cost of acceptance to model; defaults to the rate on file"},"location_id":{"type":"integer"}},"required":["target_net_cents"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/compare-programs","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.disclosure","description":"Pricing — the compliant door sign, checkout notice and receipt line for the merchant's fee program, with the posting rule that applies in its state.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/disclosure","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"checkout_notice":{},"door_sign":{},"posting_rule":{},"program":{},"receipt_line":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.display_contract","description":"Pricing — what a surface MUST and MUST NOT display for this merchant's fee program: which price is the regular price, both posted prices, the required disclosures, Visa's point-of-entry and point-of-sale placement and minimum font sizes for the channel, whether the customer must be able to cancel after seeing a surcharge, and which receipt lines may be itemised versus rolled into the price.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subtotal_cents":{"type":"integer","minimum":1},"tax_cents":{"type":"integer","default":0},"channel":{"type":"string","enum":["in_person","online","phone","invoice"],"default":"in_person"},"surface":{"type":"string","description":"catalog | menu | invoice | pos | checkout | receipt"},"tender":{"type":"string","enum":["card","cash","ach","check","other"],"default":"card"},"card_type":{"type":"string","enum":["credit","debit","prepaid","unknown"],"default":"credit"},"location_id":{"type":"integer"}},"required":["subtotal_cents"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/display-contract","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.explain_sale","description":"Pricing — explain what was charged on ONE sale, in two voices: to the customer (why the card price differs from the cash price they saw posted) and to the merchant (what they booked, what they kept, and where the difference went — including the processor's cut on a tip, which card pricing never covers). Reads the breakdown recorded at the moment of charge, never a fresh quote. NOT the same as fee.explain, which explains a merchant-account fee row rather than card pricing on a sale.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"integer","minimum":1}},"required":["transaction_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/explain-sale","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"customer":{},"disclosure":{},"error":{},"explained":{},"merchant":{},"numbers":{},"reason":{},"success":{},"transaction_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.get_settings","description":"Pricing — the merchant's fee program (surcharge / dual pricing / cash discount / convenience fee), tipping and service-charge settings, the sales-tax rate the merchant has declared (rate, label, registration, what it applies to), plus what the merchant's state allows.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/get-settings","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"allowed":{},"configured":{},"disclosure":{},"settings":{},"state":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.my_rules","description":"Pricing — every rule that applies to this merchant in their state, for the channels they actually use: whether the programme is permitted, how the state expresses its cap, which way rounding may go, what each channel must display, whether the customer must be able to cancel, and what the receipt must or must not carry.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"string"}},"program":{"type":"string","enum":["none","surcharge","dual_pricing","cash_discount","convenience_fee"]},"is_restaurant":{"type":"boolean"},"location_id":{"type":"integer"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"551","noun":"fee_law","acts_on":{"noun":"fee_law","address":"551","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/my-rules","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.posted_prices","description":"Pricing — both posted prices for one catalogue amount, for the moment a merchant SETS a price on a product, service, menu item or invoice line. Returns the cash and card price the register will actually charge, which one is the regular price, what must be displayed beside it, and any rule the merchant should know before committing to it.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","description":"one catalogue amount"},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"which price the amount is (the owner's choice while typing); omitted = the program's posted price"},"amounts_cents":{"type":"array","items":{"type":"integer"},"description":"many amounts in one call — for a catalogue, menu or invoice, so a list never has to compute its own card price"},"channel":{"type":"string","enum":["in_person","online","phone","invoice"],"default":"in_person"},"location_id":{"type":"integer"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/posted-prices","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"channel":{},"error":{},"message":{},"ok":{},"prices":{},"reason":{},"success":{},"truncated":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.preview_margin_impact","description":"Project margin + revenue impact of a price change.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"new_price":{"type":"number","minimum":0}},"required":["product_id","new_price"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"41","noun":"pricing","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/preview-margin-impact","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"current":{},"error":{},"error_code":{},"product":{},"projected":{},"reasons":{},"success":{},"verdict":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"pricing.quote","description":"Pricing — the receipt for one transaction BEFORE the card is touched: subtotal, service charge, tax, fee-program line (surcharge never on debit/prepaid, clamped to the cap), tip, total, disclosure, and why any rule was applied.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subtotal_cents":{"type":"integer","minimum":1},"tax_cents":{"type":"integer","default":0},"tender":{"type":"string","enum":["card","cash","ach","check","other"],"default":"card"},"card_type":{"type":"string","enum":["credit","debit","prepaid","unknown"],"default":"unknown"},"channel":{"type":"string","enum":["in_person","online","phone","invoice"],"default":"in_person"},"tip_mode":{"type":"string","enum":["percent","amount","roundup","none"]},"tip_value":{"type":"number","description":"percent for tip_mode=percent, cents for amount, increment cents for roundup"},"party_size":{"type":"integer"},"discount_cents":{"type":"integer","default":0,"description":"promo/coupon taken off BEFORE any fee is computed"},"card_brand":{"type":"string","enum":["visa","mastercard","amex","discover"],"description":"sets the cap — Visa 3.00%, Mastercard 4%; omit and the strictest applies"},"location_id":{"type":"integer","description":"the location's state governs the fee program"}},"required":["subtotal_cents"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/quote","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.strategy","description":"Pricing — the merchant's pricing strategy explained in their own dollars, plus exactly what every surface must render: catalogue, menu, landing page, estimate, invoice, SMS, POS, checkout and receipt. One call so no surface assembles its own answer and drifts out of agreement with the register.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"example_cents":{"type":"integer","default":10000,"description":"a sale the merchant recognises — their average ticket"},"channels":{"type":"array","items":{"type":"string"},"description":"the channels they actually sell through"},"is_restaurant":{"type":"boolean"},"location_id":{"type":"integer"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/strategy","http_method":"POST","dispatch_endpoint":null},{"name":"pricing.update_settings","description":"Pricing — change the merchant's fee program, percentage, tipping presets, service charge, or the sales-tax rate they declare. Returns `advisories`: what the state and the card-brand rules say about the choice, and what actually happens if they proceed. Only nonsense data, or a surcharge configured to reach debit/prepaid (which Solid# would itself be applying), is refused.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"fee_program":{"type":"string","enum":["none","surcharge","dual_pricing","cash_discount","convenience_fee"]},"fee_percent":{"type":"number"},"fee_fixed_cents":{"type":"integer"},"fee_label":{"type":"string"},"fee_base":{"type":"string","enum":["subtotal","subtotal_plus_tax"]},"fee_applies_to_tip":{"type":"boolean"},"fee_channels":{"type":"array","items":{"type":"string"}},"disclosure_text":{"type":"string"},"network_notified_at":{"type":"string","format":"date-time"},"tipping_enabled":{"type":"boolean"},"tip_presets":{"type":"array","items":{"type":"number"}},"tip_base":{"type":"string","enum":["pre_tax","post_tax"]},"tip_allow_custom":{"type":"boolean"},"tip_prompt":{"type":"string","enum":["before","after","receipt"]},"tax_enabled":{"type":"boolean","description":"Charge the merchant's declared sales tax on sales. Requires tax_rate_percent."},"tax_rate_percent":{"type":"number","description":"The rate the MERCHANT declares, as a percent (e.g. 7.25). Not looked up, not verified against any jurisdiction."},"tax_label":{"type":"string","description":"Receipt line label — 'Sales Tax', 'GST', 'VAT'. Defaults to 'Sales Tax'."},"tax_registration":{"type":"string","description":"The merchant's tax permit / registration number, reproduced on receipts."},"tax_applies_to":{"type":"string","enum":["all","products","services"],"description":"What the rate applies to. Many trades tax parts but not labour."},"tip_roundup_increment_cents":{"type":"integer"},"tip_max_percent":{"type":"number"},"tip_card_only":{"type":"boolean"},"service_charge_enabled":{"type":"boolean"},"service_charge_percent":{"type":"number"},"service_charge_label":{"type":"string"},"service_charge_taxable":{"type":"boolean"},"service_charge_min_party":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"550","noun":"fee_program","acts_on":{"noun":"fee_program","address":"550","domain":"Fees & pricing programmes","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_settings","when":"The result would break a pricing rule: a surcharge must round down and apply to credit only, a convenience fee must be flat, tax needs a rate.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/pricing/update-settings","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"acknowledgement":{},"advisories":{},"compliance":{},"disclosure":{},"error_code":{},"problems":{},"settings":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"product.create","description":"Create a new product in the catalog. A SKU this company already uses is refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"sku":{"type":"string","minLength":1},"price":{"type":"number","minimum":0},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"Which price was typed on a two-price program: cash or card (the card difference already in it). Omitted = the program's posted price. Stored as the posted price."},"cost_per_unit":{"type":"number","minimum":0,"default":0},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"product_type":{"type":"string","enum":["part","kit","bundle","service"],"default":"part"},"reorder_point":{"type":"integer","minimum":0,"default":10},"quantity_available":{"type":"integer","minimum":0,"default":0},"image_url":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","price","sku"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"duplicate_sku","when":"A product with that SKU exists; answered with status exists.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"name":{},"price":{},"product_id":{},"reason":{},"sku":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"product.update","description":"Edits fields on a catalog product (products): name, sku, price, cost, description, category, reorder point, on-hand quantity, active flag, image. Requires product_id; returns the list of fields changed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"price":{"type":"number","nullable":true},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"Which price was typed on a two-price program: cash or card (the card difference already in it). Omitted = the program's posted price. Stored as the posted price."},"cost_per_unit":{"type":"number","nullable":true},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"reorder_point":{"type":"integer","nullable":true},"quantity_available":{"type":"integer","nullable":true},"is_active":{"type":"boolean","nullable":true},"image_url":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"product_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"product.update_pricing","description":"Update a product's pricing fields — price, cost, MSRP, dynamic pricing.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","minimum":1},"price":{"type":"number","nullable":true},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"Which price was typed on a two-price program: cash or card (the card difference already in it). Omitted = the program's posted price. Stored as the posted price."},"cost_per_unit":{"type":"number","nullable":true},"msrp":{"type":"number","nullable":true},"dynamic_pricing_enabled":{"type":"boolean","nullable":true},"min_price_override":{"type":"number","nullable":true},"max_price_override":{"type":"number","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product/update-pricing","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"product_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"product_research.analyze_competitor","description":"Product research — competitor analysis. NOT implemented; ALWAYS RAISES. The service behind it generates traffic/keyword figures rather than measuring them.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"competitor_url":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["competitor_url"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"45","noun":"product","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product_research/analyze-competitor","http_method":"POST","dispatch_endpoint":null},{"name":"product_research.analyze_market","description":"Product research — market analysis. NOT implemented; ALWAYS RAISES. AtlasResearchService returns heuristic placeholder TAM/SAM/SOM figures (random-scaled, marked estimated=True, no sources), not market research.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"nullable":true,"type":"integer"},"industry":{"nullable":true,"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"45","noun":"product","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product_research/analyze-market","http_method":"POST","dispatch_endpoint":null},{"name":"product_research.search_keywords","description":"Product research — keyword search. NOT implemented; ALWAYS RAISES. The only service behind it generates mock volumes/CPCs with random and is not connected to the Google Ads API. Use the seo.audit_* verbs for real site data.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string"},"market":{"type":"string","default":"US"}},"required":["query"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"45","noun":"product","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/product_research/search-keywords","http_method":"POST","dispatch_endpoint":null},{"name":"promoter.assign_products","description":"Assign products to a promoter's catalog (company_id required for tenantisolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promoter_id":{"type":"string"},"product_ids":{"type":"array"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_ids","promoter_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/assign-products","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.create","description":"Adding a promoter is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"commerce:write","transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.dashboard","description":"A promoter's dashboard is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/dashboard","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.get","description":"Looking up one promoter is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.get_catalog","description":"Get the product catalog assigned to a promoter (company_id required for tenantisolation).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promoter_id":{"type":"string"}},"required":["promoter_id"]},"required_scope":null,"transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/get-catalog","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.list","description":"Listing promoters is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.set_product_commission","description":"Set commission rate for a specific product (company_id required for tenantisolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promoter_id":{"type":"string"},"product_id":{"type":"string"},"commission_rate":{"type":"number"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["commission_rate","product_id","promoter_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/set-product-commission","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.stats","description":"A promoter's performance stats is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/stats","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.unassign_product","description":"Remove a product from a promoter's catalog (company_id required for tenantisolation).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promoter_id":{"type":"string"},"product_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["product_id","promoter_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/unassign-product","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promoter.update","description":"Changing a promoter's details is not implemented yet — the partner program is parked. Refuses by name and changes nothing; tell us if you need it.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"commerce:write","transport":"http","coordinate":"560","noun":"promoter","acts_on":{"noun":"promoter","address":"560","domain":"Partners & commissions","party":"tenant_partner","whose":"the business's dealings with its promoters and affiliates"},"location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promoter/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promotion.create","description":"Creates an active discount (discounts table): kind percent, fixed, bogo or threshold, value, optional code, min subtotal, max discount and date window. Requires name; returns promotion_id and code.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"kind":{"type":"string","enum":["percent","fixed","bogo","threshold"],"default":"percent"},"value":{"type":"number","minimum":0},"code":{"type":"string","nullable":true},"min_subtotal":{"type":"number","nullable":true},"max_discount":{"type":"number","nullable":true},"starts_at":{"type":"string","format":"date-time","nullable":true},"ends_at":{"type":"string","format":"date-time","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"49","noun":"promotion","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promotion/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"code":{},"kind":{},"name":{},"promotion_id":{},"status":{},"summary":{},"value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"promotion.update","description":"Updates an existing discount (discounts, by promotion_id): name, value, code, active, max_discount or ends_at. Returns the list of updated fields, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"promotion_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"value":{"type":"number","nullable":true},"code":{"type":"string","nullable":true},"active":{"type":"boolean","nullable":true},"max_discount":{"type":"number","nullable":true},"ends_at":{"type":"string","format":"date-time","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["promotion_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"49","noun":"promotion","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/promotion/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"promotion_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposal_settings","description":"What a quote costs and what approving it means for this company: the labour rate, the materials markup and default tax the document builder prices with; whether the customer must give a purchase-order number, whether they must tick the terms, the terms and 'what is not included' text (or the knowledge-base category those come from), a deposit percent, and whether approval creates the order, the invoice and a payment link by itself. Call with no arguments to see the current rules. An empty string clears a text back to the default. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"require_po":{"type":"boolean","description":"The customer must give a purchase-order number to approve."},"require_terms_accept":{"type":"boolean","description":"They must tick that they read the terms."},"require_signature":{"type":"boolean","description":"Approving takes a drawn signature (on by default) — the proof it was them."},"terms_text":{"type":"string","description":"The contract shown on the quote. Empty clears it (falls back to the KB)."},"terms_kb_category":{"type":"string","description":"KB category holding the terms when no text is set. Default 'terms'."},"exclusions_text":{"type":"string","description":"What is NOT included. Empty clears it (falls back to the KB)."},"exclusions_kb_category":{"type":"string","description":"KB category for exclusions. Default 'exclusions'."},"deposit_percent":{"type":"number","description":"Ask for this much at approval, 0-100. 0 asks for the balance."},"auto_convert_on_approval":{"type":"boolean","description":"Approval creates the order."},"auto_invoice_on_approval":{"type":"boolean","description":"Approval creates the invoice."},"payment_link_on_approval":{"type":"boolean","description":"Approval creates a way to pay."},"payment_link_hours":{"type":"integer","minimum":1,"description":"How long that link stands. Default 72."},"valid_days":{"type":"integer","minimum":1,"description":"How long a quote stands when none is set on it. Default 30."},"labor_rate_per_hour":{"type":"number","minimum":0,"description":"What an hour of labour bills at ('4 hours' × this). Until set, drafts use $75 and say so."},"materials_markup_percent":{"type":"number","minimum":0,"maximum":500,"description":"Time & materials: a billed supplier-receipt line is cost × (1 + this/100). Default 0."},"default_tax_rate":{"type":"number","minimum":0,"maximum":100,"description":"Tax percent a new estimate or invoice starts with. Each document can change it."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"crm:write","transport":"dispatch","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"estimate.settings","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"changes":{},"current":{},"exclusions":{},"preview":{},"saved":{},"settings":{},"terms":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposals.add_item","description":"Add a line to a draft or sent proposal/estimate/bid/quote/invoice-draft; the totals are recalculated server-side. Pass a catalog.search hit (product_id or service_id) and name, price and cost come from the catalog; picking one already on the document at the same price MERGES (its quantity goes up; merged=true) unless new_line=true. An optional line (is_optional) is one the customer chooses on their page — not in the total until they do. Returns {line, merged}. For hours use proposals.add_labor; for a scanned receipt, proposals.add_receipt_lines.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"product_id":{"type":"integer","description":"A catalog product (catalog.search)"},"service_id":{"type":"integer","description":"A catalog service (catalog.search)"},"name":{"type":"string","description":"What the line is (from the catalog when an id is given)"},"unit_price":{"type":"number","minimum":0,"description":"Price each (from the catalog when an id is given)"},"source":{"type":"string","enum":["catalog","photo","voice","custom"],"description":"Where the line came from"},"quantity":{"type":"number","minimum":0,"description":"Default 1 (a merge adds this many)"},"new_line":{"type":"boolean","default":false,"description":"A catalog pick already on the document merges (quantity goes up); true adds a separate line"},"unit":{"type":"string","description":"Default \"each\""},"description":{"type":"string","description":"Detail shown under the name"},"is_optional":{"type":"boolean","description":"The customer chooses it"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/add-item","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.add_labor","description":"Add labour to a draft or sent document: hours × the company's labour rate (proposal_settings), or a rate given here. If the company never set a rate, $75 is used and rate_is_default=true — say so.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"hours":{"type":"number","exclusiveMinimum":0},"description":{"type":"string","description":"What the time is for"},"rate":{"type":"number","minimum":0,"description":"Per-hour override for this line"},"name":{"type":"string","description":"Line name, default \"Labor\""},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id","hours"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/add-labor","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.add_receipt_lines","description":"Time & materials: bill a scanned supplier receipt's lines (an expense — expense.list) on this customer's document at cost + the company's materials markup. A receipt line is billed ONCE; lines already on a document come back in already_billed. The receipt stays an expense; its lines become billable.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"vendor_purchase_id":{"type":"integer","description":"The expense (receipt) id"},"item_ids":{"type":"array","items":{"type":"integer"},"description":"Only these receipt lines"},"markup_percent":{"type":"number","minimum":0,"description":"Override the company's markup"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id","vendor_purchase_id"]},"required_scope":"crm:write","transport":"http","coordinate":"521","noun":"expense","acts_on":{"noun":"expense","address":"521","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/add-receipt-lines","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.archive","description":"Take an estimate/bid/quote/plan off the owner's list (archived=true) or bring it back (archived=false). Never deletes; works in any status; the customer's link keeps working. proposals.list archived=true lists them.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"archived":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/archive","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.change_order","description":"Change an approved estimate whose job is under way: makes version N+1 (a change order) — a draft copy of the current version's lines (source, cost, photos, optional flags kept) on the same customer and the same job. Edit it with proposals.add_item / update_item / remove_item / add_labor / add_receipt_lines / revise, then proposals.send it or have the customer sign in person — approval needs a NEW signature. The job keeps running on the current version until the customer approves; then the old version is superseded (kept, read-only, its signature still valid), the job checklist moves over keeping its ticks, and the invoice is revised (payments kept). Idempotent: an open change order is returned again. Returns it as proposals.get does, with `change` (added / removed / changed lines, old_total, new_total, difference) and `versions`.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"Any version of the approved estimate (required)"},"reason":{"type":"string","description":"Why it is changing, in a few words (shown with the change)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/change-order","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.convert_to_invoice","description":"Make a proposal/estimate/bid/quote a real invoice — the tenant's receivable in `invoices` (what invoice.list reads) — with its order. Get-or-create: asking twice returns the same invoice. A draft may convert, so \"make an invoice\" is proposals.create + lines + this.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"payment_terms":{"type":"string","enum":["due_on_receipt","net_7","net_15","net_30","net_45","net_60","net_90"]},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"510","noun":"invoice","acts_on":{"noun":"invoice","address":"510","domain":"Receivables","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/convert-to-invoice","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.create","description":"Create a draft proposal, estimate, bid, quote or invoice in the proposals table (services/proposal_service.create — the same path as POST /api/v1/proposals). Lines are optional: start blank and add them with proposals.add_item. Returns the document with its number, total and the customer's link.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Document title (required)"},"document_type":{"type":"string","description":"Type of document (proposal, estimate, bid, quote, invoice) - default: proposal"},"items":{"type":"array","description":"Line items (may be empty), each with: name (required), unit_price (required), quantity (default 1), unit (default \"each\"), description, is_optional (the customer chooses; not in the total until they do), category"},"due_date":{"type":"string","description":"Payment due date (for invoices, ISO format)"},"valid_until":{"type":"string","description":"Proposal expiration date (ISO format)"},"description":{"type":"string","description":"Scope of work or description"},"contact_id":{"type":"integer","description":"Contact/customer ID (recommended)"},"deal_id":{"type":"integer","description":"Originating deal ID (optional, links document to deal)"},"tax_rate":{"type":"string","description":"Tax rate percentage (0-100)"},"discount_percent":{"type":"string","description":"Discount percentage (0-100)"},"discount_amount":{"type":"string","description":"Fixed discount amount in dollars"},"source":{"type":"string","description":"Lead source (website, referral, social_media, cold_outreach, other)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"deal_id":{},"document_number":{},"document_type":{},"due_date":{},"id":{},"message":{},"public_token":{},"public_url":{},"status":{},"title":{},"total_amount":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposals.draft_message","description":"Write the short note that goes with an estimate or invoice to the customer (two or three plain sentences: the work, the total, what to do next) to prefill the send sheet. Sends nothing; the owner edits it and sends with proposals.send. AI-written and metered; source=template when the AI is down.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"}},"required":["proposal_id"]},"required_scope":null,"transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/draft-message","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.duplicate","description":"Start a new draft from an earlier proposal/estimate/bid/quote or a template: same lines (each keeps its source, catalog link, cost and photo), pricing and customer, a fresh number and customer link. contact_id = who the new one is for (start from a template). Nothing is sent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document or template to copy"},"contact_id":{"type":"integer","nullable":true,"description":"This company's CRM contact the new one is for"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/duplicate","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.generate_from_deal","description":"AI-generate a proposal or invoice from a deal's context.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","description":"Deal ID to generate document from (required)"},"document_type":{"type":"string","description":"Type to generate (proposal, invoice) - default: proposal"},"due_date":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id","due_date"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/generate-from-deal","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.get","description":"Read one document from the proposals table (quotes/estimates, not the invoices table) by proposal_id, tenant-scoped. Returns amounts, tax, dates, its line items (with photos), the last 20 activity entries, approval (null until the customer approved: approved_at, sent_at, viewed_at, amount, added_optional, questions_answered, signed, method), signature (intact = the record AND the live lines still match what was signed), ai_chat_enabled, is_template, and labor_rate + rate_is_default (the hourly rate hours will use — say so when it is the $75 default).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"Proposal/Invoice ID (required)"}},"required":["proposal_id"]},"required_scope":null,"transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact":{},"created_at":{},"deal_id":{},"description":{},"discount_amount":{},"discount_percent":{},"document_number":{},"document_type":{},"due_date":{},"id":{},"items":{},"public_token":{},"recent_activity":{},"sent_at":{},"status":{},"subtotal":{},"tax_amount":{},"tax_rate":{},"title":{},"total_amount":{},"valid_until":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposals.list","description":"List documents from the proposals table (estimates/bids/quotes/plans, not the invoices table): find by number, title or customer (query), several types or statuses comma-separated, sort (newest/oldest/amount_high/amount_low/updated), archived (only archived; default hides them), limit ≤100 + offset. Returns documents with customer, total, archived and has_invoice, the total, and counts per status for filter chips.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_type":{"type":"string","description":"Type, or several comma-separated (estimate,bid,quote,plan,proposal,invoice)"},"status":{"type":"string","description":"Status, or several comma-separated (draft,sent,viewed,accepted,rejected,expired,cancelled)"},"query":{"type":"string","description":"Find by number, title, customer name or email"},"sort":{"type":"string","enum":["newest","oldest","amount_high","amount_low","updated"],"default":"newest"},"archived":{"type":"boolean","default":false,"description":"true = only archived documents"},"offset":{"type":"integer","minimum":0,"default":0},"contact_id":{"type":"integer","description":"Filter by contact (this customer's last estimate: + limit 1)"},"deal_id":{"type":"integer","description":"Filter by deal"},"templates":{"type":"boolean","default":false,"description":"true = only saved templates (the Start from picker)"},"limit":{"type":"integer","description":"Max results (default 25)"}}},"required_scope":null,"transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"documents":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposals.remove_item","description":"Remove one line from a draft or sent proposal/estimate/bid/quote; the totals are recalculated.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"item_id":{"type":"integer","description":"The line's id, from proposals.get items[].id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id","item_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/remove-item","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.revise","description":"Change a draft's lines from what the owner said — \"make that four hours\", \"take the second line off\", \"add two of those\". Read against this draft's lines and this company's own catalog; each change goes through proposals.add_item / update_item / remove_item / add_labor. Returns applied, skipped (with why) and the document after — read them back, never claim a change that is in skipped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"instruction":{"type":"string","minLength":1,"description":"What the owner said, as words"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id","instruction"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/revise","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.save_as_template","description":"Keep a proposal/estimate/bid/quote's lines as a template — a starting point for the next one (a copy with no customer, never sent, off every normal list). proposals.list templates=true lists templates; proposals.duplicate with contact_id starts an estimate from one for a customer.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"name":{"type":"string","description":"The template's name (default: the document's title)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/save-as-template","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.send","description":"Send a document (proposal, estimate, bid, quote, invoice) to the customer by email, text or both: their link to review it, choose optional lines and approve (services/proposal_service.deliver — the same path as POST /api/v1/proposals/{id}/send). Marked sent ONLY when a delivery went; `channels` reports each. Sending one they already have goes as a reminder; one they declined goes back to sent. Prefill `message` with proposals.draft_message.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"Document ID (required)"},"email":{"type":"string","description":"Send here instead of the linked customer's email"},"message":{"type":"string","description":"The owner's own note, shown in the email"},"channel":{"type":"string","enum":["email","text","both"],"default":"email","description":"email, text the same signing link (fails honestly while texting is not registered), or both"},"phone":{"type":"string","description":"For a text: send here instead of the linked customer's phone"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"is_template","when":"The document is a template — duplicate it first.","override":null,"code_in_response":false},{"code":"not_sendable","when":"The document is accepted or converted (only draft, sent, viewed or rejected can be sent).","override":null,"code_in_response":false},{"code":"empty_document","when":"The document has no line items.","override":null,"code_in_response":false},{"code":"no_email","when":"Sending by email with no address passed and none on the contact.","override":"email","code_in_response":false},{"code":"no_phone","when":"Sending by text with no number passed and none on the contact.","override":"phone","code_in_response":false}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"document_number":{},"id":{},"message":{},"public_url":{},"sent_to":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"proposals.update","description":"Change a draft or sent proposal/estimate/bid/quote: title, description, contact_id (who it is for — one of this company's CRM contacts), valid_until, due_date, tax_rate, discount_percent, discount_amount, ai_chat_enabled, or a manual status (draft, cancelled, expired, rejected). Sent/accepted are set by proposals.send and the customer's page, never here.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"title":{"type":"string"},"description":{"type":"string"},"contact_id":{"type":"integer","nullable":true,"description":"This company's CRM contact"},"valid_until":{"type":"string","description":"ISO date"},"due_date":{"type":"string","description":"ISO date"},"tax_rate":{"type":"number","minimum":0,"maximum":100},"discount_percent":{"type":"number","minimum":0,"maximum":100},"discount_amount":{"type":"number","minimum":0},"ai_chat_enabled":{"type":"boolean","description":"The customer's page answers questions"},"status":{"type":"string","enum":["draft","cancelled","expired","rejected"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/update","http_method":"POST","dispatch_endpoint":null},{"name":"proposals.update_item","description":"Change one line on a draft or sent proposal/estimate/bid/quote — name, description, quantity, unit_price, unit, is_optional or is_selected. Only the fields passed change; totals are recalculated.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"proposal_id":{"type":"integer","description":"The document's id (proposals.list / proposals.get)"},"item_id":{"type":"integer","description":"The line's id, from proposals.get items[].id"},"name":{"type":"string"},"description":{"type":"string"},"quantity":{"type":"number","minimum":0},"unit_price":{"type":"number","minimum":0},"unit":{"type":"string"},"is_optional":{"type":"boolean","description":"Turning it on leaves it out of the total until the customer adds it"},"is_selected":{"type":"boolean","description":"Whether the line counts in the total"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["proposal_id","item_id"]},"required_scope":"crm:write","transport":"http","coordinate":"360","noun":"estimate","acts_on":{"noun":"estimate","address":"360","domain":"Estimates & jobs","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/proposals/update-item","http_method":"POST","dispatch_endpoint":null},{"name":"quiz.result","description":"Score a quiz run and return the outcome band, in this tenant's own words. Works for a right/wrong quiz, a scored assessment (lead qualification, readiness) or a recommendation quiz with no right answers at all. The result is explainable — `breakdown` shows which answers produced the score. An outcome may carry a verb, so the top band can book the appointment rather than congratulate the respondent; the verb name is returned, you call it.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"playbook_id":{"type":"string"},"answered":{"type":"object","nullable":true},"kb_sub_code":{"type":"integer","nullable":true},"lang":{"type":"string","default":"en"}},"required":["playbook_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"quiz","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/quiz/result","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"playbook_id":{},"status":{},"summary":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"receipt.send_email","description":"Emails the customer receipt for one sale (transactions.id) to an address via the tenant's routed email sender; content is the breakdown recorded at charge time. Returns sent only on provider success.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"integer","minimum":1},"to_email":{"type":"string","format":"email"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transaction_id","to_email"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"640","noun":"email_message","acts_on":{"noun":"email_message","address":"640","domain":"Email","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/receipt/send-email","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"message_id":{},"provider":{},"status":{},"summary":{},"to_email":{},"transaction_id":{},"transaction_ref":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"referral.link","description":"A link the happy customer forwards themselves, attributed back to them. ⛔ We never contact the person they name — that person did not give anyone their number, and an unsolicited message to them is the merchant's TCPA/A2P exposure. Whoever arrives lands in the merchant's own CRM.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"referrer_contact_id":{"type":"integer","nullable":true},"base_url":{"type":"string","default":""}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"99","noun":"referral","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/referral/link","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"refund.issue","description":"Refund a prior charge through the company's connected processor. Pass amount_cents to do a partial refund; omit for a full refund. IRREVERSIBLE — owner role only + typed phrase including the amount and charge id.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"charge_id":{"type":"string","description":"The processor's charge id (returned by charge_invoice)."},"amount_cents":{"type":"integer","description":"Refund amount in cents. Omit for full refund.","minimum":1},"reason":{"type":"string","description":"Refund reason (stored in audit log).","maxLength":500},"processor":{"type":"string","description":"Optional processor override."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["charge_id"]},"required_scope":"payments:write","transport":"http","coordinate":"531","noun":"refund","acts_on":{"noun":"refund","address":"531","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/refund/issue","http_method":"POST","dispatch_endpoint":null},{"name":"relate.get","description":"The whole neighbourhood of an entity in the hierarchy graph: its parents, children, siblings, cousins, ancestors, and descendants. Works for any entity type (location/rep/product/kit/…).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"node_type":{"type":"string"},"node_id":{"type":"integer"}},"required":["node_id","node_type"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"relate","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/relate/get","http_method":"POST","dispatch_endpoint":null},{"name":"relate.link","description":"Connect two entities in the platform hierarchy graph: locations, reps, or products/kits. relation ∈ parent_of (the hierarchy backbone — cycle-checked) | member_of | related_to | substitute_for. Tenant-scoped and idempotent.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"from_type":{"type":"string"},"from_id":{"type":"integer"},"to_type":{"type":"string"},"to_id":{"type":"integer"},"relation":{"type":"string","default":"parent_of","enum":["parent_of","member_of","related_to","substitute_for"]},"note":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["from_id","from_type","to_id","to_type"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"09","noun":"relate","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/relate/link","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"from":{},"id":{},"ok":{},"relation":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"relate.unlink","description":"Remove a specific edge between two entities in the hierarchy graph.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"from_type":{"type":"string"},"from_id":{"type":"integer"},"to_type":{"type":"string"},"to_id":{"type":"integer"},"relation":{"type":"string","default":"parent_of","enum":["parent_of","member_of","related_to","substitute_for"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["from_id","from_type","to_id","to_type"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"09","noun":"relate","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/relate/unlink","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"ok":{},"removed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"reminder.cancel","description":"Cancel one of my reminders. REST: DELETE /api/v1/reminders/{id}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"reminder_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["reminder_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"reminder","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/reminder/cancel","http_method":"POST","dispatch_endpoint":null},{"name":"reminder.list","description":"My reminders still to come (include_done=true for all). Read-only. REST: GET /api/v1/reminders.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_done":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"39","noun":"reminder","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/reminder/list","http_method":"POST","dispatch_endpoint":null},{"name":"reminder.set","description":"Remind ME — the person asking, never the customer. Exactly one trigger: `at` (ISO time; a time with no zone is the business's clock), `before_appointment_id` with `offset_minutes` (default 60; it moves when the appointment moves), or `on` = {verb: \"appointment.complete\", appointment_id} (\"when Nina's job is done\"). Delivered as an inbox notification and a phone push. REST: POST /api/v1/reminders.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message":{"type":"string","minLength":1},"at":{"type":"string","format":"date-time","nullable":true},"before_appointment_id":{"type":"integer","nullable":true},"offset_minutes":{"type":"integer","minimum":0,"nullable":true},"on":{"type":"object","nullable":true,"properties":{"verb":{"type":"string","enum":["appointment.complete"]},"appointment_id":{"type":"integer"}}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"reminder","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/reminder/set","http_method":"POST","dispatch_endpoint":null},{"name":"reminder.setup","description":"Turn automated SMS appointment reminders on or off for this company. When on, booked appointments get reminder texts before the appointment. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"true to enable SMS appointment reminders, false to disable."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enabled"]},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"reminder","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/reminder/setup","http_method":"POST","dispatch_endpoint":null},{"name":"reminder_cancel","description":"Cancel one of the owner's own reminders.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"reminder_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["reminder_id"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"39","noun":"reminder","location":"svc.api","same_as":"reminder.cancel","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"reminder_list","description":"The owner's own reminders still to come (include_done for all). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_done":{"type":"boolean"}}},"required_scope":null,"transport":"dispatch","coordinate":"39","noun":"reminder","location":"svc.api","same_as":"reminder.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"reminder_set","description":"Remind the OWNER (never the customer): 'remind me at 3', 'an hour before Ray', 'when Nina's job is done'. Exactly one of: at (ISO; no zone = the business's clock), before_appointment_id with offset_minutes (default 60), or on = {verb: 'appointment.complete', appointment_id}.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message":{"type":"string"},"at":{"type":"string"},"before_appointment_id":{"type":"integer"},"offset_minutes":{"type":"integer"},"on":{"type":"object","properties":{"verb":{"type":"string","enum":["appointment.complete"]},"appointment_id":{"type":"integer"}}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message"]},"required_scope":"calendar:write","transport":"dispatch","coordinate":"39","noun":"reminder","location":"svc.api","same_as":"reminder.set","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"report_deal_pipeline","description":"Return the current sales pipeline grouped by stage. Counts and total amount per stage for OPEN deals only (excludes won/lost/closed/cancelled). Read-only. Use this when the user asks 'where are my deals?' or 'show me the pipeline'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"33","noun":"deal","location":"svc.api","same_as":"deal.pipeline_report","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"by_stage":{},"company_id":{},"ok":{},"open_deals":{},"total_pipeline_value_usd":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"report_revenue_summary","description":"Return this company's revenue summary for the last N days. Reports TWO ledgers under `summary`: order_revenue/total_revenue (collected checkout/POS/ecommerce orders) and closed_deal_revenue (booked value of won/paid CRM deals — how sales-led businesses earn), plus total_sales (both combined) and closed_deal_revenue_all_time. Read-only. If order_revenue is 0, check closed_deal_revenue before reporting '$0 sales'. DO NOT fabricate numbers.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","description":"Lookback window in days. Default 30.","minimum":1,"maximum":365}}},"required_scope":null,"transport":"dispatch","coordinate":"500","noun":"books","acts_on":{"noun":"books","address":"500","domain":"Books & ledger","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":"books.revenue_summary","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"ok":{},"summary":{},"window_days":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"report_transactions","description":"List this company's transactions (orders) for a time window, optionally filtered to declines or refunds. Use this when the user asks to see orders/transactions/sales for a period, or asks about failed, declined, or refunded payments — e.g. 'show me declines this year', 'what failed in the last 90 days', 'how much did we refund YTD'. Returns a count, the summed amount, and the matching rows. Read-only. DECLINES AND REFUNDS ARE DIFFERENT THINGS and this verb keeps them apart: a decline is money that never arrived (the processor refused the charge), a refund is money that arrived and went back. Do not add them together or describe a refund as a failed payment. The window is ALWAYS reported back in `window` — state it when you answer, and never imply a result covers all time. DO NOT fabricate numbers; if count is 0, say so for THAT window and offer a wider one.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"period":{"type":"string","enum":["today","30days","60days","90days","6months","ytd","mtd"],"description":"Time window. Default '30days'. Use 'ytd' for year-to-date and '6months' for the last 180 days."},"status":{"type":"string","enum":["all","declines","refunds"],"description":"'declines' = processor refusals, money that never arrived. 'refunds' = money that arrived and went back, including partial refunds. Default 'all'."},"limit":{"type":"integer","description":"Maximum rows to return. Default 100, max 500.","minimum":1,"maximum":500}}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"transactions","location":"svc.api","same_as":"transactions.report","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"count":{},"ok":{},"status_filter":{},"total_amount":{},"transactions":{},"truncated":{},"window":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"request_review","description":"Text a customer a one-tap link to leave this company's business a Google review — the close-the-job follow-up that drives the local reputation flywheel. Honors SMS opt-out/TCPA. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact id to text (must have a phone)."},"custom_message":{"type":"string","description":"Optional custom SMS body. The review link is appended automatically."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"39","noun":"request","location":"svc.api","same_as":"review.request","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"contact_id":{},"message":{},"message_preview":{},"preflight":{},"review_link":{},"status":{},"to_phone":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.competitors.analyze","description":"Analyze a competitor's digital presence and SEO.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string","description":"Competitor domain to analyze (e.g., \"competitor.com\")"}},"required":["domain"]},"required_scope":null,"transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/competitors.analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"backlinks":{},"company_id":{},"content_gaps":{},"domain":{},"domain_authority":{},"estimated_traffic":{},"referring_domains":{},"strengths":{},"top_keywords":{},"weaknesses":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.content.suggestions","description":"Get AI-powered content suggestions based on topic research.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"topic":{"type":"string","description":"Topic to generate content suggestions for"},"content_type":{"type":"string","description":"Type of content (blog, landing_page, email, social)"}},"required":["topic"]},"required_scope":null,"transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/content.suggestions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"competitor_content_gaps":{},"content_type":{},"suggestions":{},"topic":{},"trending_angles":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.keywords.search","description":"Search for keywords and get SEO metrics.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","description":"Search query for keyword research"},"include_related":{"type":"boolean","description":"Include related keyword suggestions"},"max_results":{"type":"integer","description":"Maximum number of results to return"}},"required":["query"]},"required_scope":null,"transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/keywords.search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"keywords":{},"query":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.market.analyze","description":"Analyze market size and growth potential.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"industry":{"type":"string","description":"Industry to analyze (e.g., \"SaaS CRM\", \"E-commerce\")"},"geography":{"type":"string","description":"Geographic market (default: \"United States\")"}},"required":["industry"]},"required_scope":null,"transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/market.analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"assumptions":{},"company_id":{},"confidence":{},"geography":{},"growth_rate":{},"industry":{},"sam":{},"sam_formatted":{},"som":{},"som_formatted":{},"sources":{},"tam":{},"tam_formatted":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.projects.create","description":"Create a new research project to organize findings.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name"},"description":{"type":"string","description":"Optional project description"},"tags":{"type":"string","description":"Optional list of tags for organization"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/projects.create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"created_at":{},"description":{},"id":{},"name":{},"tags":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.projects.list","description":"List all research projects for a company.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Maximum number of results"},"offset":{"type":"integer","description":"Pagination offset"}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/projects.list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"limit":{},"offset":{},"projects":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"research.projects.save_data","description":"Store research results on a research_projects row by project_id; data_type keywords, market or competitors picks which JSON column is overwritten with data. Returns success, project_id and saved_at.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"integer","description":"Research project ID"},"data_type":{"type":"string","description":"Type of data (keywords, market, competitors)"},"data":{"type":"object","description":"Research data to save"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["data","data_type","project_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"99","noun":"research","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/research/projects.save-data","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"data_type":{},"error":{},"project_id":{},"saved_at":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"review.ask","description":"The review ask: which link to send and the words they approved. ⛔ Passing an offer is REFUSED — Google treats incentivised reviews as fake & misleading content and penalises the merchant's listing. A recovery gesture to an unhappy customer is fine; a gesture in the same breath as an ask is not.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"draft":{"type":"string","default":""},"platform":{"type":"string","nullable":true},"offer":{"type":"object","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"incentive_offer_refused","when":"An offer was attached — incentivised reviews are refused.","override":null,"code_in_response":false},{"code":"no_destination","when":"No review link is configured (for that platform).","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/ask","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"review.destinations","description":"Where this company can send a happy customer to leave a review. Every destination is LINK ONLY — the customer posts in their own account, because no API anywhere permits posting on their behalf. An empty list means ask for nothing rather than improvise a URL.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/destinations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"review.draft_response","description":"Draft a brief, warm, professional reply to a customer review on behalf of this company. Returns suggested text for a human to review and post — it does NOT publish anything. Handles low-rating reviews gracefully (apologize, invite offline contact).","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"review_text":{"type":"string","description":"The customer's review text."},"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Star rating 1-5, if known."},"reviewer_name":{"type":"string","description":"Reviewer's name, if known."}},"required":["review_text"]},"required_scope":null,"transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/draft-response","http_method":"POST","dispatch_endpoint":null},{"name":"review.followup","description":"What to do once a review lands: thank a promoter personally, or 'let me do better' for a detractor — with the largest live make-good attached. Never asks a reviewer to amend their review.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"rating":{"type":"integer","minimum":1},"reviewer":{"type":"string","default":""},"contact_id":{"type":"integer","nullable":true}},"required":["rating"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/followup","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"contact_id":{},"rating":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"review.list","description":"This company's recent Google reviews and overall rating. Read-only. Use it to spot reviews that need a response or to gauge reputation.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Max reviews to return. Default 10."}}},"required_scope":null,"transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/list","http_method":"POST","dispatch_endpoint":null},{"name":"review.moderate","description":"Moderate a product review for this company — set its status to approved, rejected, or spam. (Drafting a reply to a Google/business review is draft_review_response.)","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"review_id":{"type":"integer","description":"Review id to moderate."},"status":{"type":"string","enum":["approved","rejected","spam"],"description":"New moderation status."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["review_id","status"]},"required_scope":"marketing:write","transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/moderate","http_method":"POST","dispatch_endpoint":null},{"name":"review.request","description":"Text a customer a one-tap link to leave this company's business a Google review — the close-the-job follow-up that drives the local reputation flywheel. Honors SMS opt-out/TCPA. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact id to text (must have a phone)."},"custom_message":{"type":"string","description":"Optional custom SMS body. The review link is appended automatically."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/request","http_method":"POST","dispatch_endpoint":null},{"name":"review.set_destination","description":"Store the review link this tenant copied from their own business profile. https only — a link a browser warns about costs the review and some of the trust that earned it. Link only: no API anywhere permits posting a review on a customer's behalf.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"url":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","url"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"34","noun":"review","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/review/set-destination","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"review_moderate","description":"Moderate a product review for this company — set its status to approved, rejected, or spam. (Drafting a reply to a Google/business review is draft_review_response.)","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"review_id":{"type":"integer","description":"Review id to moderate."},"status":{"type":"string","enum":["approved","rejected","spam"],"description":"New moderation status."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["review_id","status"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"34","noun":"review","location":"svc.api","same_as":"review.moderate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"review_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"roles.list","description":"List this company's roles and their safe-write permissions (propose/stage/approve/publish/rollback), showing which are custom vs platform defaults. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"29","noun":"roles","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/roles/list","http_method":"POST","dispatch_endpoint":null},{"name":"roles.reset","description":"Reset a role to the platform default permissions (removes the company's custom override). Owner only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"role_name":{"type":"string","description":"Role to reset to defaults."}},"required":["role_name"]},"required_scope":null,"transport":"http","coordinate":"29","noun":"roles","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/roles/reset","http_method":"POST","dispatch_endpoint":null},{"name":"roles.set","description":"Define what a role may do in the write-safety pipeline. permissions is a list from: write.propose, write.stage, write.approve, write.publish, write.rollback, write.irreversible. Owner only — this controls who can publish AI changes vs. who must get approval.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"role_name":{"type":"string","description":"Role to configure, e.g. call_center_rep."},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions to grant this role (replaces its current set)."}},"required":["role_name","permissions"]},"required_scope":null,"transport":"http","coordinate":"29","noun":"roles","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/roles/set","http_method":"POST","dispatch_endpoint":null},{"name":"roles_list","description":"List this company's roles and their safe-write permissions (propose/stage/approve/publish/rollback), showing which are custom vs platform defaults. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"roles","location":"svc.api","same_as":"roles.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"roles":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"roles_reset","description":"Reset a role to the platform default permissions (removes the company's custom override). Owner only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"role_name":{"type":"string","description":"Role to reset to defaults."}},"required":["role_name"]},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"roles","location":"svc.api","same_as":"roles.reset","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"roles_set","description":"Define what a role may do in the write-safety pipeline. permissions is a list from: write.propose, write.stage, write.approve, write.publish, write.rollback, write.irreversible. Owner only — this controls who can publish AI changes vs. who must get approval.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"role_name":{"type":"string","description":"Role to configure, e.g. call_center_rep."},"permissions":{"type":"array","items":{"type":"string"},"description":"Permissions to grant this role (replaces its current set)."}},"required":["role_name","permissions"]},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"roles","location":"svc.api","same_as":"roles.set","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"run_local_seo_audit","description":"Run a Local SEO audit for this company — checks the Google Business Profile, recommended categories, NAP/citation consistency, and scores the local presence. Returns the findings. Read-only analysis.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"83","noun":"seo","location":"svc.api","same_as":"seo.audit","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sales.advance","description":"Move a deal to the next pipeline stage. Auto-advances if no stage specified.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"stage":{"type":"string","nullable":true,"description":"Target stage (omit to auto-advance)"},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/advance","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"deal_id":{},"error":{},"new_stage":{},"old_stage":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.close","description":"Close a deal as won or lost. Logs the outcome and reason.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1},"outcome":{"type":"string","enum":["won","lost"],"default":"won"},"close_reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["deal_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/close","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"amount":{},"deal_id":{},"error":{},"old_stage":{},"outcome":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.compare","description":"Period-over-period sales comparison (mtd/qtd/ytd). Shows deltas and AI analysis of trends.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"period":{"type":"string","enum":["mtd","qtd","ytd"],"default":"mtd"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/compare","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"avg_deal_value":{},"deals_created":{},"deals_lost":{},"deals_won":{},"new_leads":{},"revenue":{},"win_rate":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.followup","description":"Pending follow-ups split into overdue and upcoming, ranked by due date. Shows tasks requiring sales action.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":25}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/followup","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"overdue":{},"total_pending":{},"upcoming":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.forecast","description":"Revenue forecast: total/monthly/YTD revenue, average deal value, and pipeline breakdown by stage.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/forecast","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"pipeline":{},"revenue":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.motion_describe","description":"The owner says in plain words how follow-ups should go (\"wait 2 days before chasing quotes, always ask me before review requests\") → a PREVIEW of step changes {changes: [{step, field, from, to, why}], unmatched}. Writes NOTHING: show the owner, then apply each change with sales.motion_set_step. REST: POST /api/v1/sales-motion/describe.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"text":{"type":"string","maxLength":2000}},"required":["text"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/motion-describe","http_method":"POST","dispatch_endpoint":null},{"name":"sales.motion_get","description":"The business's SALES MOTION — how leads, quotes, appointments and follow-ups go — as stages (lead → contacted → quote → booked → confirmed → reminded → visit → done → review) and steps. Each step: trigger, wait, action, wording, channel and autonomy (auto = the system does it, ask = a Needs-you card, off). A new company runs the default motion. Pass `step` for one. Read-only. REST: GET /api/v1/sales-motion.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"the step's key, e.g. booking_confirmation, quote_follow_up, confirm_request","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/motion-get","http_method":"POST","dispatch_endpoint":null},{"name":"sales.motion_history","description":"What the sales motion did: each step that fired, for whom, and the outcome (done, asked, waiting, failed, skipped) in plain words. Filter by step. Read-only. REST: GET /api/v1/sales-motion/history.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"the step's key, e.g. booking_confirmation, quote_follow_up, confirm_request","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"nullable":true},"before_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/motion-history","http_method":"POST","dispatch_endpoint":null},{"name":"sales.motion_set_step","description":"Change ONE step of the sales motion: autonomy (auto | ask | off — each step lists what it allows), wait (in the step's unit), wording (the customer's words; only the step's {tokens}), channel (auto | email | sms), or reset=true for the default. \"Always do this\" on a card = autonomy auto. Refuses with a sentence. REST: PATCH /api/v1/sales-motion/steps/{step}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"the step's key, e.g. booking_confirmation, quote_follow_up, confirm_request"},"autonomy":{"type":"string","enum":["auto","ask","off"],"nullable":true},"wait":{"type":"integer","minimum":0,"nullable":true},"wording":{"type":"string","maxLength":600,"nullable":true},"cancel_wording":{"type":"string","maxLength":600,"nullable":true},"channel":{"type":"string","enum":["auto","email","sms"],"nullable":true},"reset":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["step"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"autonomy_not_allowed","when":"The autonomy is not one of the step's options.","override":null,"code_in_response":true},{"code":"wait_not_editable","when":"The step happens right away and has no editable wait.","override":null,"code_in_response":true},{"code":"wait_out_of_range","when":"The wait is outside the step's range.","override":null,"code_in_response":true},{"code":"wording_not_editable","when":"The step sends nothing, or has no separate cancellation wording.","override":null,"code_in_response":true},{"code":"unknown_tokens","when":"The wording uses {tokens} the step cannot fill.","override":null,"code_in_response":true},{"code":"channel_not_allowed","when":"A channel is set on a step that sends nothing.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/motion-set-step","http_method":"POST","dispatch_endpoint":null},{"name":"sales.nurture","description":"Send a nurture step to a contact — logs outreach activity and creates a 3-day follow-up task.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","minimum":1,"description":"CRM contact id (crm_contacts.id — the id search_contacts / crm.contacts.search return as contact id). NOT a lead_submissions id: promote a form lead with crm_lead_promote first and use the contact_id it returns."},"channel":{"type":"string","enum":["email","sms","call_script","voice"],"default":"email"},"message":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["lead_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/nurture","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"activity_id":{},"channel":{},"contact_id":{},"contact_name":{},"error":{},"followup_due":{},"followup_task_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.opportunities","description":"AI-identified growth opportunities — analyzes pipeline health, stale deals, high-value prospects, and industry-specific seasonal patterns.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/opportunities","http_method":"POST","dispatch_endpoint":null},{"name":"sales.outreach","description":"Generate personalized outreach copy (email, SMS, or call script) using the contact's history and industry KB context.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","minimum":1,"description":"CRM contact id (crm_contacts.id — the id search_contacts / crm.contacts.search return as contact id). NOT a lead_submissions id: promote a form lead with crm_lead_promote first and use the contact_id it returns."},"channel":{"type":"string","enum":["email","sms","call_script"],"default":"email"}},"required":["lead_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/outreach","http_method":"POST","dispatch_endpoint":null},{"name":"sales.pipeline","description":"Full sales pipeline view: deal counts and values per stage, total pipeline value, win rate.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/pipeline","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"conversion_rate":{},"lost_value":{},"open_pipeline_value":{},"stages":{},"total_deals":{},"total_pipeline_value":{},"won_value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.prospects","description":"High-value prospects ranked by lead score. Returns stats summary and top contacts ready for outreach.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":25}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/prospects","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"message":{},"ok":{},"prospects":{},"reason":{},"stats":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.qualify","description":"Promote a lead to a qualified deal. Creates a Deal record linked to the contact with an activity log entry.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","minimum":1,"description":"CRM contact id (crm_contacts.id — the id search_contacts / crm.contacts.search return as contact id). NOT a lead_submissions id: promote a form lead with crm_lead_promote first and use the contact_id it returns."},"title":{"type":"string","nullable":true},"value":{"type":"number","nullable":true,"description":"Deal value in dollars"},"stage":{"type":"string","default":"Qualified"},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["lead_id"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/qualify","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"contact_name":{},"deal_id":{},"error":{},"stage":{},"status":{},"title":{},"value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.report","description":"Sales performance report for a period (mtd, qtd, ytd). Deals, revenue, leads, and customer metrics.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"period":{"type":"string","enum":["mtd","qtd","ytd"],"default":"mtd"}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/report","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"customers":{},"leads":{},"period":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.score","description":"AI-score a lead (0-100) with industry-specific reasoning using KB context. Returns signals, risks, and recommended action.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lead_id":{"type":"integer","minimum":1,"description":"CRM contact id (crm_contacts.id — the id search_contacts / crm.contacts.search return as contact id). NOT a lead_submissions id: promote a form lead with crm_lead_promote first and use the contact_id it returns."}},"required":["lead_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/score","http_method":"POST","dispatch_endpoint":null},{"name":"sales.sequence_create","description":"Create a multi-step outreach sequence. Enrolls contacts and schedules tasks for each step.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"lead_ids":{"type":"array","items":{"type":"integer"},"nullable":true,"description":"CRM contact ids (crm_contacts.id), not lead_submissions ids."},"steps":{"type":"array","items":{"type":"object"},"nullable":true,"description":"Array of {channel, delay_days, message}"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"crm:write","transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/sequence-create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contacts_enrolled":{},"invalid_lead_ids":{},"sequence_name":{},"status":{},"steps":{},"tasks_created":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.sources","description":"Lead source performance — per-funnel counts, deals, conversions, and average lead score over a configurable lookback window.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"default":30}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/sources","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"period_days":{},"sources":{},"total_leads":{},"total_won":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.suggest","description":"AI-powered next-best-action for a deal. Considers stage, activity recency, and industry KB to rank 3 actions.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"deal_id":{"type":"integer","minimum":1}},"required":["deal_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/suggest","http_method":"POST","dispatch_endpoint":null},{"name":"sales.velocity","description":"Deal velocity — stage-to-stage conversion rates showing how fast deals move through the funnel.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"default":30}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/velocity","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"lost_count":{},"period_days":{},"stages":{},"total_deals":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales.win_rate","description":"Win/loss analysis — deal outcomes by stage plus lead score tier distribution (A/B/C/D/F breakdown).","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":365,"default":30}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"30","noun":"sales","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sales/win-rate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"funnel":{},"period_days":{},"tiers":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sales_motion_describe","description":"The owner says how follow-ups should go in plain words ('wait 2 days before chasing quotes, always ask me before review requests') → a PREVIEW of step changes {changes: [{step, field, from, to, why}], unmatched}. Writes nothing. Show the owner, then apply each change with sales_motion_set_step. Say what was unmatched.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"text":{"type":"string","maxLength":2000}},"required":["text"]},"required_scope":null,"transport":"dispatch","coordinate":"30","noun":"sales","location":"svc.api","same_as":"sales.motion_describe","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sales_motion_get","description":"How this business's leads, quotes, appointments and follow-ups go — its SALES MOTION: stages lead → contacted → quote → booked → confirmed → reminded → visit → done → review, each step with its trigger, wait, action, wording, channel and autonomy (auto = done on its own, ask = a Needs-you card, off). Use it to answer 'what happens when someone books', 'do we chase quotes'. Pass `step` for one. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"step key, e.g. booking_confirmation, quote_follow_up, confirm_request"}}},"required_scope":null,"transport":"dispatch","coordinate":"30","noun":"sales","location":"svc.api","same_as":"sales.motion_get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sales_motion_history","description":"What the sales motion did: each step that fired, for whom, and the outcome (done, asked, waiting, failed, skipped) in plain words. 'Did Dana get her reminder?' Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"step key, e.g. booking_confirmation, quote_follow_up, confirm_request"},"limit":{"type":"integer","minimum":1,"maximum":200},"before_id":{"type":"integer"}}},"required_scope":null,"transport":"dispatch","coordinate":"30","noun":"sales","location":"svc.api","same_as":"sales.motion_history","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sales_motion_set_step","description":"Change ONE step of the sales motion: autonomy (auto | ask | off), wait (in the step's unit), wording (the customer's words; only the step's {tokens}), channel (auto | email | sms), cancel_wording (appointment_changed only: the cancellation notice's own words), or reset=true for the default. 'Always do this' on a follow-up card = autonomy auto for its motion_step.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"step":{"type":"string","enum":["lead_first_reply","lead_follow_up","quote_follow_up","booking_confirmation","confirm_request","confirm_by_reply","reschedule_by_reply","cancel_by_reply","confirmed_ack","appointment_changed","reminder_3d","reminder_1d","reminder_2h","no_show_rebook","refill_canceled_slot","invoice_after_job","review_ask","review_not_asked"],"description":"step key, e.g. booking_confirmation, quote_follow_up, confirm_request"},"autonomy":{"type":"string","enum":["auto","ask","off"]},"wait":{"type":"integer","minimum":0},"wording":{"type":"string","maxLength":600},"cancel_wording":{"type":"string","maxLength":600},"channel":{"type":"string","enum":["auto","email","sms"]},"reset":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["step"]},"required_scope":"crm:write","transport":"dispatch","coordinate":"30","noun":"sales","location":"svc.api","same_as":"sales.motion_set_step","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sandbox.diff","description":"Show all changes made in the active sandbox session.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/diff","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox.exit","description":"Discard sandbox — all sandbox-only changes are deleted.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/exit","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox.fork","description":"Fork a sandbox session — all writes will be tagged with this session until promote or exit.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"scope":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/fork","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox.promote","description":"Promote sandbox changes to production — makes all sandbox-tagged entities live.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/promote","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox.snapshot","description":"Snapshot the company's sandbox environment for restore points. Owner role + typed phrase. Stub until sandbox engine ships.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"stub","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/snapshot","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox.status","description":"Check if a sandbox session is active for this company.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sandbox/status","http_method":"POST","dispatch_endpoint":null},{"name":"sandbox_snapshot","description":"Snapshot the company's sandbox environment for restore points. Owner role + typed phrase. Stub until sandbox engine ships.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"dispatch","coordinate":"07","noun":"sandbox","location":"svc.api","same_as":"sandbox.snapshot","status":"stub","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"label":{},"preflight":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"schedule.add_attendee","description":"Adds a team member (attendee_user_id) as an attendee on a tenant appointment (appointment_attendees). Idempotent if already attending. Requires appointment_id and attendee_user_id; returns status added.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"attendee_user_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"schedule","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/schedule/add-attendee","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appointment_id":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"schedule.create","description":"Create an appointment (title + ISO start_time; end_time or the service's length). Runs the same booking as appointment.book — business clock, hours, clashes, the contact kept as the appointment's person — and books it as scheduled rather than confirmed. Returns appointment_id.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time","nullable":true},"contact_id":{"type":"integer","nullable":true},"service_id":{"type":"integer","nullable":true},"notes":{"type":"string","nullable":true},"location":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["start_time","title"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"schedule","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/schedule/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appointment_id":{},"start_time":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"schedule.send_reminder","description":"Sends a reminder about an appointment to the company owner (or an admin) as an inbox notification plus mobile push. Not sent to the customer. Returns reminder_sent or no_recipient.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"appointment_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["appointment_id"],"additionalProperties":true},"required_scope":"calendar:write","transport":"http","coordinate":"39","noun":"schedule","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/schedule/send-reminder","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"appointment_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"security.disable_2fa","description":"Security — remove a user's second factor. NOT EXECUTABLE from an agent surface; always raises. It is an account-security downgrade for the re-authenticated account holder only, and the service behind it resolves users with no company filter. Use DELETE /api/v1/auth/2fa/totp.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"25","noun":"security","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/security/disable-2fa","http_method":"POST","dispatch_endpoint":null},{"name":"security.enable_2fa","description":"Security — enrol a user in 2FA. NOT EXECUTABLE from an agent surface; always raises. Enrolment hands out a shared secret and needs a code from the account holder's authenticator — use POST /api/v1/auth/2fa/totp/setup then /verify-setup.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"method":{"type":"string","default":"totp"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"25","noun":"security","location":"svc.api","same_as":null,"status":"disabled","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/security/enable-2fa","http_method":"POST","dispatch_endpoint":null},{"name":"send_agent_message","description":"Send a message from ADA to another agent for coordination. If requires_response=True the receiving agent is enqueued to respond via the real ConversationManager pipeline (uses their full system prompt + tools). Otherwise the message just lands in the target's inbox for next time they're active.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_agent_type":{"type":"string","description":"Receiver agent_type from the registry (e.g. 'customer_service', 'sales', 'marketing', 'finance'). Preferred over target_agent_id."},"target_agent_id":{"type":"integer","description":"Per-company DB agent id. Use target_agent_type when possible."},"message_body":{"type":"string","description":"The message. 1-8000 chars.","minLength":1,"maxLength":8000},"subject":{"type":"string","description":"Optional subject line (max 255 chars).","maxLength":255},"message_type":{"type":"string","enum":["request","response","notification","escalation"],"description":"Default 'notification'."},"priority":{"type":"string","enum":["low","normal","high","critical"],"description":"Default 'normal'."},"requires_response":{"type":"boolean","description":"If true, the receiving agent is enqueued (Celery) to respond. Default false (notify only)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message_body"]},"required_scope":"agents:write","transport":"dispatch","coordinate":"10","noun":"agent","location":"svc.api","same_as":"agent.message","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"celery_task_id":{},"communication_id":{},"created_at":{},"from_agent":{},"message":{},"message_type":{},"preflight":{},"priority":{},"requires_response":{},"status":{},"to_agent":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"seo.audit","description":"Run a Local SEO audit for this company — checks the Google Business Profile, recommended categories, NAP/citation consistency, and scores the local presence. Returns the findings. Read-only analysis.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit","http_method":"POST","dispatch_endpoint":null},{"name":"seo.audit_get","description":"Fetch one SEO audit run (seo_audits) by audit_id for this tenant. Returns its target URL, overall score, HTTP status, load time and created_at; use seo.audit_pages for per-page findings.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"audit_id":{"type":"integer","minimum":1}},"required":["audit_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit-get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audit":{},"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"seo.audit_latest","description":"Return the most recent SEO audit for the tenant.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit-latest","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audit":{},"ok":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"seo.audit_list","description":"List recent SEO audits for the tenant (newest first).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100,"default":20}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit-list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audits":{},"count":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"seo.audit_pages","description":"Fetch per-page audit findings for an SEO audit. Optional severity filter.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"audit_id":{"type":"integer","minimum":1},"severity":{"type":"string","enum":["critical","high","medium","low"],"nullable":true}},"required":["audit_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit-pages","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audit_id":{},"count":{},"ok":{},"pages":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"seo.audit_run","description":"Run a fresh SEO audit synchronously against a target URL. Persists a SEOAudit row + per-page findings.","shape":"aggregate","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_url":{"type":"string","minLength":1},"triggered_by":{"type":"string","default":"agent"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_url"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"83","noun":"seo","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/seo/audit-run","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"audit_id":{},"created_at":{},"load_time_ms":{},"ok":{},"overall_score":{},"reason":{},"status_code":{},"summary":{},"target_url":{},"triggered_by":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.attach","description":"Map/attach ANY code to a product or variant — SKU, UPC, EAN, GTIN, ISBN, QR, barcode, or custom. For a QR pass a url to map it to a destination (rendered + stored). GS1 kinds are check-digit validated. The create/edit side of mapping serialization.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["sku","upc","ean","gtin","isbn","qr","barcode","custom"]},"value":{"type":"string","nullable":true},"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true},"url":{"type":"string","nullable":true},"symbology":{"type":"string","nullable":true},"is_primary":{"type":"boolean","default":false},"render":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["kind"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/attach","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"identifier_id":{},"image_url":{},"kind":{},"ok":{},"payload":{},"value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.barcode","description":"Create a GS1 barcode (UPC-A / EAN-13 / GTIN-14) for a product or variant — with a correct mod-10 check digit. Supplies an internal restricted-circulation code when the tenant has no GS1 prefix; optionally renders a PNG and persists to the product's identifiers.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true},"kind":{"type":"string","default":"ean","enum":["upc","ean","gtin"]},"value":{"type":"string","nullable":true},"sequence":{"type":"integer","nullable":true},"render":{"type":"boolean","default":false},"persist":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/barcode","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.configure","description":"Set per-unit config on a serial — shelf life (expires_at), markdown/sell-by (discount_after), holder (rep / truck / location / customer), and free-form attributes. Dates accept YYYY-MM-DD or ISO.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"serial":{"type":"string"},"expires_at":{"type":"string","nullable":true},"discount_after":{"type":"string","nullable":true},"holder_type":{"type":"string","nullable":true},"holder_id":{"type":"integer","nullable":true},"location_id":{"type":"integer","nullable":true},"attributes":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["serial"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/configure","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.detach","description":"Delete a mapped identifier by id — the delete side of mapping serialization.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"identifier_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["identifier_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/detach","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"identifier_id":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.gs1id","description":"Generate or validate GS1 keys beyond GTIN: SSCC (logistics unit / pallet, AI 00), GLN (location, AI 414), GTIN-8 (small packs), and UDI (medical-device DI+PI). With a value it validates; otherwise it generates from base/sequence.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"key":{"type":"string","enum":["sscc","gln","gtin8","udi"]},"value":{"type":"string","nullable":true},"base":{"type":"string","nullable":true},"sequence":{"type":"integer","nullable":true},"gtin":{"type":"string","nullable":true},"serial":{"type":"string","nullable":true},"lot":{"type":"string","nullable":true},"expiry":{"type":"string","nullable":true},"issuer":{"type":"string","default":"gs1"}},"required":["key"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/gs1id","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"key":{},"not_implemented":{},"udi":{},"valid":{},"value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.gs1link","description":"Build the international GS1 identity for a product: a GS1 Digital Link URL + element string (what a modern QR/DataMatrix encodes for EU FMD / US DSCSA) plus the GS1 prefix's issuing country. Accepts a gtin or a product/variant with a minted GS1 code.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"gtin":{"type":"string","nullable":true},"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true},"serial":{"type":"string","nullable":true},"lot":{"type":"string","nullable":true},"expiry":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/gs1link","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"digital_link":{},"element_string":{},"error":{},"gtin":{},"message":{},"ok":{},"prefix":{},"reason":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.inventory","description":"Answer operational questions over serialized units: what a rep holds (holder_type=rep, holder_id), what store has a product (product_id + location_id), what's expiring / needs moving (expiring_within_days). Returns units with days-to-expiry.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","nullable":true},"location_id":{"type":"integer","nullable":true},"holder_type":{"type":"string","nullable":true},"holder_id":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true},"expiring_within_days":{"type":"integer","nullable":true},"limit":{"type":"integer","default":100}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/inventory","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.list","description":"List the identifiers (SKU/UPC/EAN/GTIN/QR/barcode) and per-unit serial count attached to a product or variant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"identifiers":{},"message":{},"ok":{},"product_id":{},"reason":{},"serial_count":{},"variant_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.locate","description":"Find where something is: resolve a code (serial / barcode / SKU / lot / GLN) and report its known physical location — GLN + GPS. Live GPS / on-a-truck tracking is a device step (flagged, not faked).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/locate","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.location","description":"Serialize a location — assign/generate its GLN (Global Location Number) and set GPS coordinates. GPS is manual today; on-site capture is a device step.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"location_id":{"type":"integer"},"gln":{"type":"string","nullable":true},"latitude":{"type":"number","nullable":true},"longitude":{"type":"number","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["location_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/location","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.lot","description":"Suggest a lot or batch number (LOT-YYYYMMDD-xxxxxx / BATCH-YYYYMMDD-xxxxxx). Read-only; the batch record itself is created by the inventory verbs.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"kind":{"type":"string","default":"lot","enum":["lot","batch"]}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/lot","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"kind":{},"number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.national","description":"National/regional track-and-trace codes (EU-FMD, US-DSCSA, RU Chestny ZNAK, CN-DTC, IN, BR, KR, SA). With a code, registers an externally-issued code against a product (works today); without, attempts generation (documented not-yet-implemented per market).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"scheme":{"type":"string"},"code":{"type":"string","nullable":true},"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true},"gtin":{"type":"string","nullable":true},"serial":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["scheme"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/national","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"code":{},"detail":{},"error":{},"identifier_id":{},"not_implemented":{},"ok":{},"scheme":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.nfc","description":"NFC. Register an externally-read NFC tag UID onto a physical unit (serial + nfc_uid) so a later NFC read resolves to that exact unit — the working path today. Writing an NDEF payload to a physical tag is a hardware step (documented, stubbed).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"serial":{"type":"string","nullable":true},"nfc_uid":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/nfc","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.primary","description":"Set an identifier as the primary code for its kind on its product/variant (unsets siblings of the same kind).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"identifier_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["identifier_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/primary","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"identifier_id":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.qr","description":"Render a QR code for a payload (product URL, SKU, or serial) as a self-contained base64 PNG data URL. Read-only; nothing persisted.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"payload":{"type":"string"}},"required":["payload"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/qr","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"image_url":{},"payload":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.recall","description":"Recall a lot / batch / SKU: persist the recall and flip every affected physical unit (unit_serials) to 'recalled'. Returns the recall id and the blast radius (batches matched, units affected).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"lot_number":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"batch_id":{"type":"integer","nullable":true},"severity":{"type":"string","default":"medium","enum":["info","low","medium","high","critical"]},"action":{"type":"string","default":"quarantine","enum":["quarantine","return_to_vendor","destroy","notify_customers"]},"source":{"type":"string","nullable":true},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/recall","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.report","description":"Serialization coverage/health report — how many products have SKUs, GS1 barcodes, and serials, and where the gaps are.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/report","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.resolve","description":"Scan a code (serial, barcode/UPC/EAN/GTIN, SKU, or lot/batch number) and get the exact product, variant, physical unit, or lot it identifies. The read side of the scanner loop.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"code":{"type":"string"}},"required":["code"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/resolve","http_method":"POST","dispatch_endpoint":null},{"name":"serialize.rfid","description":"RFID/EPC. Register an externally-read EPC onto a physical unit (serial + epc) so a later RFID read resolves to that exact unit — the working path today. Encoding an EPC from a GTIN (writing a tag) is a documented not-yet-implemented hardware step.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"serial":{"type":"string","nullable":true},"epc":{"type":"string","nullable":true},"gtin":{"type":"string","nullable":true},"unit_serial_seq":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/rfid","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"epc":{},"error":{},"not_implemented":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.serial","description":"Mint count per-unit serial numbers for a product/variant/batch and persist them (status 'available'). This is what makes scan -> exact-unit and recall-by-lot possible.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"count":{"type":"integer","default":1,"minimum":1,"maximum":10000},"product_id":{"type":"integer","nullable":true},"variant_id":{"type":"integer","nullable":true},"batch_id":{"type":"integer","nullable":true},"location_id":{"type":"integer","nullable":true},"prefix":{"type":"string","default":"SN"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/serial","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"batch_id":{},"error":{},"minted":{},"product_id":{},"serials":{},"variant_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.sku","description":"Suggest a SKU: a variant SKU when base_sku + attributes are given (e.g. TSHIRT-001 + {color,size} -> TSHIRT-001-BLU-L), otherwise a base product SKU from a name. Read-only suggestion; assignment happens at product/variant create.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","nullable":true},"base_sku":{"type":"string","nullable":true},"attributes":{"type":"object","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/sku","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"kind":{},"message":{},"ok":{},"reason":{},"sku":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.status","description":"Transition per-unit serials through their lifecycle (available -> allocated -> shipped -> returned, or recalled/void). Stamps an order_id when allocating/shipping to an order. This is the seam the fulfillment flow calls to reserve and ship physical units.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"serials":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["available","allocated","shipped","returned","recalled","void"]},"order_id":{"type":"integer","nullable":true},"notes":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["serials","status"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"updated":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"serialize.suggest","description":"'These serial items can be optimized' — concrete suggestions from catalog gaps (products missing a barcode, not yet serialized). The optimizations Jake surfaces.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","default":20}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"40","noun":"serialize","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/serialize/suggest","http_method":"POST","dispatch_endpoint":null},{"name":"service.create","description":"Create a new bookable service in the catalog.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"price":{"type":"number","nullable":true},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"Which price was typed on a two-price program: cash or card (the card difference already in it). Omitted = the program's posted price. Stored as the posted price."},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"default_duration_min":{"type":"integer","minimum":5,"maximum":480,"default":60},"currency":{"type":"string","default":"USD"},"taxable":{"type":"boolean","default":true},"visible_online":{"type":"boolean","default":true},"capacity_per_slot":{"type":"integer","minimum":1,"default":1},"requires_on_site":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/service/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"duration_min":{},"price":{},"service_id":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"service.update","description":"Edits a bookable service in the tenant service catalog (service_catalog): title, price, description, category, duration, online visibility, taxable. Requires service_id; returns the fields changed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"service_id":{"type":"integer","minimum":1},"title":{"type":"string","nullable":true},"price":{"type":"number","nullable":true},"price_basis":{"type":"string","enum":["cash","card"],"nullable":true,"description":"Which price was typed on a two-price program: cash or card (the card difference already in it). Omitted = the program's posted price. Stored as the posted price."},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"default_duration_min":{"type":"integer","nullable":true},"visible_online":{"type":"boolean","nullable":true},"taxable":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["service_id"],"additionalProperties":true},"required_scope":"commerce:write","transport":"http","coordinate":"450","noun":"catalog_item","acts_on":{"noun":"catalog_item","address":"450","domain":"Catalog","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/service/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"service_id":{},"status":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"set_brand_tokens","description":"Set this company's brand DESIGN tokens. Pass any of colors / typography / shape / assets as objects — they DEEP-MERGE into the current brand (send only what changes). Colors are hex; typography is font families + scale.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"colors":{"type":"object","description":"e.g. {\"primary\":\"#0EA5E9\",\"accent\":\"#F97316\"}."},"typography":{"type":"object","description":"e.g. {\"heading_font\":\"Inter\",\"body_font\":\"Inter\"}."},"shape":{"type":"object","description":"e.g. {\"border_radius\":\"1rem\"}."},"assets":{"type":"object","description":"e.g. {\"logo_url\":\"...\",\"favicon\":\"...\"}."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"pages:write","transport":"dispatch","coordinate":"77","noun":"brand","location":"svc.api","same_as":"brand.set_tokens","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"design":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"set_brand_truth","description":"Set this company's brand truth — the voice/positioning the AI grounds on: tone, target audience, mission, unique selling proposition, personality, values, and preferred/forbidden words. Pass only the fields to change; one record per company (upsert).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tone":{"type":"string","description":"e.g. professional, friendly, luxury."},"target_audience":{"type":"string"},"company_mission":{"type":"string"},"unique_selling_proposition":{"type":"string"},"brand_personality":{"type":"array","items":{"type":"string"},"description":"e.g. ['innovative','trustworthy']."},"company_values":{"type":"array","items":{"type":"string"}},"preferred_keywords":{"type":"array","items":{"type":"string"}},"forbidden_words":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"brand:write","transport":"dispatch","coordinate":"77","noun":"brand","location":"svc.api","same_as":"brand.set_truth","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"created":{},"ok":{},"updated_fields":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"set_capability","description":"Record whether this company offers a specific capability/service, so the AI answers callers correctly. offered=true means 'we do this'; offered=false means 'we explicitly do NOT' (prevents the AI from over-promising).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","description":"Grouping, e.g. 'services', 'payment', 'hours'."},"capability_name":{"type":"string","description":"The capability, e.g. 'emergency service'."},"offered":{"type":"boolean","description":"True = offered, False = explicitly not offered. Default true."},"details":{"type":"string","description":"Optional detail shown to the AI."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["category","capability_name"]},"required_scope":"company:write","transport":"dispatch","coordinate":"17","noun":"capability","location":"svc.api","same_as":"capability.set","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"capability":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"set_contact_consent","description":"Record a contact's communication consent for a channel (voice / sms / email), WITH provenance — the audited, lawful path to enable AI outreach to that contact. `basis` says how consent was obtained: 'web_form' (written), 'verbal_inbound' (they called/opted in), or 'operator_attested' (you attest a known relationship, e.g. the owner's own number). IMPORTANT: operator_attested is a WEAKER basis for transactional / informational contact only — it is NOT accepted for marketing consent, which requires written (web_form) consent under TCPA.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id to record consent for."},"channel":{"type":"string","enum":["voice","sms","email"],"description":"Communication channel this consent covers."},"basis":{"type":"string","enum":["web_form","verbal_inbound","operator_attested"],"description":"How the consent was obtained (its lawful basis + provenance source)."},"consent_level":{"type":"string","enum":["transactional","marketing"],"description":"transactional (informational — reminders/confirmations) or marketing. Default transactional."},"disclosure_text":{"type":"string","description":"Optional — the exact language the contact saw/agreed to (stored as proof)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","channel","basis"]},"required_scope":"gdpr:write","transport":"dispatch","coordinate":"31","noun":"contact","location":"svc.api","same_as":"contact.set_consent","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"basis":{},"channel":{},"consent_level":{},"contact_id":{},"ok":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"settlement.run_payout","description":"Trigger a payout from the processor's balance to the merchant's bank. Omit amount_cents for full available balance. IRREVERSIBLE — owner role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":1},"currency":{"type":"string","default":"USD"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"541","noun":"settlement","acts_on":{"noun":"settlement","address":"541","domain":"Settlement","party":"tenant_processor","whose":"the business's account with its payment processor"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/settlement/run-payout","http_method":"POST","dispatch_endpoint":null},{"name":"setup_drip_sequence","description":"Create an automated drip email sequence for this company — fires on a trigger (new contact, deal stage change, tag added, manual, or webhook) and can stop on reply/click/conversion. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Sequence name, e.g. 'New lead nurture'."},"trigger_type":{"type":"string","enum":["contact_created","deal_stage_changed","tag_added","manual","webhook"],"description":"What starts the sequence."},"description":{"type":"string","description":"Optional description."},"stop_on_reply":{"type":"boolean","description":"Stop if the contact replies. Default false."},"stop_on_click":{"type":"boolean","description":"Stop if the contact clicks a link. Default false."},"stop_on_conversion":{"type":"boolean","description":"Stop if the deal is won. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","trigger_type"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"09","noun":"setup","location":"svc.api","same_as":"drip.setup","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"is_active":{},"name":{},"ok":{},"preflight":{},"sequence_id":{},"trigger_type":{},"would_create":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"setup_reminders","description":"Turn automated SMS appointment reminders on or off for this company. When on, booked appointments get reminder texts before the appointment. Reversible. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"true to enable SMS appointment reminders, false to disable."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["enabled"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"09","noun":"setup","location":"svc.api","same_as":"reminder.setup","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"ok":{},"preflight":{},"sms_appointment_reminders":{},"would_set":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.addresses","description":"List the addresses (subdomain + custom-domain bindings) for a site.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1}},"required":["site_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/addresses","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"addresses":{},"canonical_url":{},"count":{},"custom_domains":{},"ok":{},"reason":{},"site_id":{},"subdomains":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.create","description":"Provision a new site for the tenant via services.site_provisioner. Same path the dashboard's site-create flow uses.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string"},"template_name":{"type":"string","default":"basecamp"},"url":{"type":"string","nullable":true},"custom_config":{"type":"object","nullable":true},"is_live":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"domain":{},"is_live":{},"name":{},"ok":{},"reason":{},"site_id":{},"site_type":{},"slug":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.delete","description":"Delete a site. Soft-deletes by default (sets deleted_at); pass hard=true for permanent removal. Tenant-scoped.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1},"hard":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"mode":{},"ok":{},"reason":{},"site_id":{},"slug":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.generate_multipage","description":"Drive Blueprint + Alex to generate a full multi-page website for the tenant.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"style":{"type":"string","nullable":true},"industry":{"type":"string","nullable":true},"pages":{"type":"array","items":{"type":"string"},"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/generate-multipage","http_method":"POST","dispatch_endpoint":null},{"name":"site.get","description":"Fetch one of the tenant's sites (sites table) by site_id. Returns slug, name, site type, published flag, settings and the business addresses shown on the site.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1}},"required":["site_id"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"site":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.get_by_slug","description":"Fetch one of the tenant's sites (sites table) by its slug. Returns id, name, site type, published and live flags, and domain; use site.get for settings and addresses.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1}},"required":["slug"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/get-by-slug","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"site":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.get_design_theme","description":"This tenant's current site design theme plus every theme it could be set to. Reports whether the stored value is one the renderer recognises — nothing validated this field before, so a company can hold a value that silently renders as 'default'.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/get-design-theme","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"choices":{},"company_id":{},"design_theme":{},"error":{},"is_recognised":{},"renders_as":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.get_display","description":"What this site currently shows: the visibility toggles (services, products, appointments, pricing, promotions, phone, chat widget) and the chrome fields (primary_color, CTA, footer, announcement, social, nav, locales) — each with the default the renderer applies when unset, and which ones this tenant has actually chosen.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/get-display","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"company_id":{},"error":{},"explicitly_set":{},"field_help":{},"fields":{},"note":{},"set_with":{},"success":{},"toggles":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.list","description":"List all sites belonging to the tenant — name, slug, subdomain, custom_domain, publish state.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_deleted":{"type":"boolean","default":false}},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"sites":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.regenerate","description":"Regenerate the tenant's entire website from scratch via Blueprint + Alex.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"style":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/regenerate","http_method":"POST","dispatch_endpoint":null},{"name":"site.set_design_theme","description":"Set this tenant's site design theme: default, glassmorphism, neo-brutalism, soft, corporate, playful, dark, elegant. Validated — an unknown value is REFUSED with the legal list, because the renderer would otherwise fall back to 'default' and report success while changing nothing. Merges into website_settings; every other setting is preserved.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"theme":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["theme"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/set-design-theme","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"choices":{},"company_id":{},"design_theme":{},"error":{},"label":{},"message":{},"previous_theme":{},"settings_preserved":{},"success":{},"valid_themes":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.set_display","description":"Turn parts of the site on or off and set its chrome. Pass any of the keys below; the rest of website_settings is preserved. An unrecognised key is REFUSED by name rather than written — the column is free-form JSON, so a typo would otherwise save, render nothing, and report success. show_powered_by is not settable: its default comes from the tier.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"show_services":{"type":"boolean","nullable":true},"show_products":{"type":"boolean","nullable":true},"show_appointments":{"type":"boolean","nullable":true},"show_pricing":{"type":"boolean","nullable":true},"show_promotions":{"type":"boolean","nullable":true},"show_phone":{"type":"boolean","nullable":true},"chat_widget_enabled":{"type":"boolean","nullable":true},"primary_color":{"type":"string","nullable":true},"cta_text":{"type":"string","nullable":true},"cta_link":{"type":"string","nullable":true},"footer_text":{"type":"string","nullable":true},"announcement":{"type":"object","nullable":true},"social_links":{"type":"array","nullable":true},"nav_links":{"type":"array","nullable":true},"default_locale":{"type":"string","nullable":true},"supported_locales":{"type":"array","nullable":true},"booking_mode":{"type":"string","enum":["book","request"],"nullable":true,"description":"website booking: pick a time, or send a request"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"unknown_display_keys","when":"A key the renderer does not read (show_powered_by is set by tier, never here).","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/set-display","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"changed":{},"company_id":{},"detail":{},"error":{},"fields":{},"keys":{},"message":{},"settings_preserved":{},"success":{},"toggles":{},"unknown":{},"valid":{},"valid_fields":{},"valid_toggles":{},"value":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.set_motion_profile","description":"Set the site-wide Cinematic Motion dial that drives the animation intensity of the whole site: 'subtle' (minimal), 'balanced' (default), or 'cinematic' (full motion). Applies to a site by id, or the company's primary site if site_id is omitted.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"motion_profile":{"type":"string","enum":["subtle","balanced","cinematic"],"description":"subtle | balanced | cinematic."},"site_id":{"type":"integer","description":"Site id; omit for the primary site."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["motion_profile"]},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/set-motion-profile","http_method":"POST","dispatch_endpoint":null},{"name":"site.templates","description":"List every available site template — read-only catalog.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/templates","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"templates":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.tier_features","description":"Return the feature limits / enabled flags for a given subscription tier — used to gate template selection.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tier":{"type":"string","enum":["starter","builder","professional","enterprise"]}},"required":["tier"],"additionalProperties":true},"required_scope":"pages:read","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/tier-features","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"features":{},"ok":{},"tier":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site.update","description":"Update a site's mutable fields (name, domain, custom_config, live/published flags). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"domain":{"type":"string","nullable":true},"custom_config":{"type":"object","nullable":true},"is_live":{"type":"boolean","nullable":true},"is_published":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"71","noun":"site","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/site/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"fields_changed":{},"ok":{},"reason":{},"site":{},"site_id":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site_create","description":"Provision a NEW website/site for this company from a template. Reuses the same provisioning path the dashboard uses. Reversible (the site can be deleted).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","description":"URL slug for the site (lowercase, dashes)."},"template_name":{"type":"string","description":"Starter template (default 'basecamp')."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"71","noun":"site","location":"svc.api","same_as":"site.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"site_delete","description":"Delete a site (soft-delete by default — sets deleted_at, reversible). Pass hard=true only to permanently remove it. Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to delete."},"hard":{"type":"boolean","description":"Permanent delete instead of soft-delete. Default false."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"71","noun":"site","location":"svc.api","same_as":"site.delete","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"site_set_motion_profile","description":"Set the site-wide Cinematic Motion dial that drives the animation intensity of the whole site: 'subtle' (minimal), 'balanced' (default), or 'cinematic' (full motion). Applies to a site by id, or the company's primary site if site_id is omitted.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"motion_profile":{"type":"string","enum":["subtle","balanced","cinematic"],"description":"subtle | balanced | cinematic."},"site_id":{"type":"integer","description":"Site id; omit for the primary site."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["motion_profile"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"71","noun":"site","location":"svc.api","same_as":"site.set_motion_profile","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"motion_profile":{},"ok":{},"site_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"site_update","description":"Update a site's mutable fields (name, description, published state). Tenant-scoped.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"site_id":{"type":"integer","description":"sites.id to update."},"name":{"type":"string"},"description":{"type":"string"},"is_published":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["site_id"]},"required_scope":"pages:write","transport":"dispatch","coordinate":"71","noun":"site","location":"svc.api","same_as":"site.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"sms.send","description":"Send a text through the Switchboard — recipient by E.164 `to` or CRM `contact_id` ('text my mom'); the FROM number is resolved server-side from the board (the caller's own line when they have one, else the company default). TCPA consent, DNC, and the first-contact AI disclaimer are enforced by the SMS service and cannot be bypassed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"message":{"type":"string"},"to":{"type":"string","nullable":true,"pattern":"^\\+?[0-9]{7,15}$"},"contact_id":{"type":"integer","nullable":true},"from_line_id":{"type":"integer","nullable":true},"message_type":{"type":"string","enum":["transactional","marketing"],"default":"transactional"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["message"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"630","noun":"text_message","acts_on":{"noun":"text_message","address":"630","domain":"Texts","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"contact_has_no_phone","when":"Only contact_id given and that contact has no phone.","override":"to","code_in_response":true},{"code":"invalid_from_line","when":"from_line_id is not an active SMS line of this company, or is someone else's personal line.","override":null,"code_in_response":true},{"code":"contact_opted_out","when":"The contact opted out of texts.","override":null,"code_in_response":true},{"code":"marketing_consent_not_granted","when":"A marketing text to a contact without granted SMS consent.","override":null,"code_in_response":true},{"code":"marketing_rate_limit_3_per_day","when":"A 4th marketing text to this number in 24 hours.","override":null,"code_in_response":true},{"code":"rate_limit_10_per_day","when":"An 11th text of any kind to this number in 24 hours.","override":null,"code_in_response":true},{"code":"consent_check_failed_marketing_blocked","when":"The consent lookup failed and the text is marketing.","override":null,"code_in_response":true},{"code":"blocked_dnc","when":"The number is on the Do-Not-Call or block list.","override":null,"code_in_response":true},{"code":"consent_unreadable","when":"The Do-Not-Call check could not be read; fails closed.","override":null,"code_in_response":true},{"code":"no_sending_number","when":"No sending line and no shared number is configured.","override":null,"code_in_response":false},{"code":"budget_exceeded","when":"The company's included SMS budget is used up.","override":null,"code_in_response":true}],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/sms/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"contact_id":{},"contact_name":{},"detail":{},"error":{},"from_line":{},"sent":{},"sms_log_id":{},"status":{},"to":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"sms_send","description":"Send an SMS to a CRM contact owned by this company. Returns a confirmation card; the SMS is NOT sent until the user clicks Confirm. Runs sms.send: it goes out from the caller's own line or the company default, and consent, opt-out, DNC and the opt-out notice are enforced by the SMS service.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact ID owned by this company."},"message":{"type":"string","description":"SMS body. Plain text. Max 1000 chars."},"intent":{"type":"string","description":"Optional one-sentence reason for the message."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","message"]},"required_scope":"comms:write","transport":"dispatch","coordinate":"630","noun":"text_message","acts_on":{"noun":"text_message","address":"630","domain":"Texts","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"sms.send","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"audit_id":{},"contact":{},"contact_id":{},"from_line":{},"message":{},"message_length":{},"message_preview":{},"preflight":{},"sms_log_id":{},"status":{},"to_phone":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.accounts","description":"List all social media accounts connected for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/accounts","http_method":"POST","dispatch_endpoint":null},{"name":"social.connect","description":"Connect a social media platform via OAuth.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/connect","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"oauth_url":{},"platform":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.create_content","description":"Social — add an item to the company's content library. Really persists it; nothing is published. The author is the caller, from the session.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"content_type":{"type":"string","default":"post"},"hashtags":{"nullable":true,"type":"array","items":{"type":"string"}},"allowed_platforms":{"nullable":true,"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","title"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/create-content","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"content_id":{},"content_type":{},"status":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.create_post","description":"Social — create a DRAFT post against the company's connected account for a platform. Really persists it; nothing is published. Publish with social.publish_post.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"content":{"type":"string"},"media_urls":{"nullable":true,"type":"array","items":{"type":"string"}},"post_type":{"type":"string","default":"text"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content","platform"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/create-post","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"account_id":{},"platform":{},"post_id":{},"post_status":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.delete_post","description":"Delete a previously-posted social post. Typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"post_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","post_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/delete-post","http_method":"POST","dispatch_endpoint":null},{"name":"social.disconnect","description":"Deletes the tenant's connected social account row (social_media_accounts) for the given platform. Returns disconnected, or not_connected if none exists.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/disconnect","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"platform":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.list_connections","description":"Lists the tenant's connected social media accounts (social_media_accounts). Returns platform, account_name and connection status per account, plus total.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/list-connections","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connections":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.post_now","description":"Post to a connected social platform NOW. Provider-agnostic — specify platform name (linkedin / x / meta / tiktok). Typed phrase required (public brand reputation).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"text":{"type":"string","maxLength":5000},"media_urls":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","text"]},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/post-now","http_method":"POST","dispatch_endpoint":null},{"name":"social.publish_post","description":"Social — publish an existing draft PUBLICLY to the connected platform. Really publishes. A platform rejection is returned as status=failed with the error, never as published.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"post_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["post_id"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/publish-post","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_message":{},"platform":{},"platform_post_id":{},"platform_post_url":{},"post_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social.schedule_post","description":"Schedule a social post for a future ISO datetime.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"text":{"type":"string","maxLength":5000},"send_at":{"type":"string","description":"ISO 8601 datetime"},"media_urls":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","text","send_at"]},"required_scope":"marketing:write","transport":"http","coordinate":"92","noun":"social","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/social/schedule-post","http_method":"POST","dispatch_endpoint":null},{"name":"social_accounts_list","description":"List all social media accounts connected for this company.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{}},"required_scope":null,"transport":"dispatch","coordinate":"92","noun":"social","location":"svc.api","same_as":"social.accounts","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"accounts":{},"count":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social_post_create","description":"Post to a connected social platform NOW. Provider-agnostic — specify platform name (linkedin / x / meta / tiktok). Typed phrase required (public brand reputation).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"text":{"type":"string","maxLength":5000},"media_urls":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","text"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"92","noun":"social","location":"svc.api","same_as":"social.post_now","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"platform":{},"preflight":{},"preview":{},"result":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social_post_delete","description":"Delete a previously-posted social post. Typed phrase required.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"post_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","post_id"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"92","noun":"social","location":"svc.api","same_as":"social.delete_post","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"platform":{},"post_id":{},"preflight":{},"result":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"social_post_schedule","description":"Schedule a social post for a future ISO datetime.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"platform":{"type":"string"},"text":{"type":"string","maxLength":5000},"send_at":{"type":"string","description":"ISO 8601 datetime"},"media_urls":{"type":"array","items":{"type":"string"}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["platform","text","send_at"]},"required_scope":"marketing:write","transport":"dispatch","coordinate":"92","noun":"social","location":"svc.api","same_as":"social.schedule_post","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"platform":{},"preflight":{},"result":{},"send_at":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ssl.issue_certificate","description":"SSL — reconcile the TLS certificate for one of this company's custom domains. Probes the live endpoint and reports the OBSERVED status (may honestly be 'pending'); Caddy performs issuance. Raises if the domain is not this company's.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"domain":{"type":"string"},"admin_email":{"nullable":true,"type":"string","description":"Recipient of the certificate-issued notice; defaults to the company contact."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["domain"],"additionalProperties":true},"required_scope":"domains:write","transport":"http","coordinate":"79","noun":"ssl","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ssl/issue-certificate","http_method":"POST","dispatch_endpoint":null},{"name":"staff.create","description":"Add a person to the team who can be booked. A staff member is not a login: link an existing login with user_id, or invite one with team.invite using the same email — the login is linked to this person when the invite is accepted. REST: POST /api/v1/staff (which also takes invite=true for a signed-in owner/admin).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"skills":{"type":"array","items":{"type":"string"},"description":"what they can do, e.g. [\"hvac\", \"water-heater\"]","nullable":true},"working_hours":{"type":"object","description":"weekday → list of [start, end] in 24h HH:MM, the business's clock: {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}. A missing day = no hours recorded; [] = not working that day. {} clears them.","additionalProperties":{"type":"array","items":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2}},"nullable":true},"default_duration_min":{"type":"integer","minimum":5,"maximum":1440,"nullable":true},"capacity_per_day":{"type":"integer","minimum":1,"maximum":200,"nullable":true},"on_call":{"type":"boolean","nullable":true,"description":"on call = bookable at any hour"},"color_index":{"type":"integer","minimum":0,"maximum":63,"nullable":true},"title":{"type":"string","maxLength":120,"nullable":true,"description":"their role, e.g. \"Lead installer\""},"employment_status":{"type":"string","enum":["employee","contractor","temp","intern"],"nullable":true,"description":"how they work for the business. An installer or subcontractor who is one person is \"contractor\"; a subcontracting FIRM is a vendor (vendor.create, is_1099)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/create","http_method":"POST","dispatch_endpoint":null},{"name":"staff.deactivate","description":"Take someone off the team for booking: never offered in availability, never assigned. Their open jobs are NOT moved — they come back in open_appointments to reassign. Their login (if any) is untouched — that is team.deactivate_user. REST: POST /api/v1/staff/{id}/deactivate.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/deactivate","http_method":"POST","dispatch_endpoint":null},{"name":"staff.get","description":"One staff member in full plus their load: open jobs in the next 14 days (per day, and the next five in full) and time off still to come. Read-only. REST: GET /api/v1/staff/{id}.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1}},"required":["staff_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/get","http_method":"POST","dispatch_endpoint":null},{"name":"staff.hours","description":"Set a staff member's weekly working hours (replaces them). Bookings and availability use these. REST: PUT /api/v1/staff/{id}/hours.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"hours":{"type":"object","description":"weekday → list of [start, end] in 24h HH:MM, the business's clock: {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}. A missing day = no hours recorded; [] = not working that day. {} clears them.","additionalProperties":{"type":"array","items":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2}}},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id","hours"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/hours","http_method":"POST","dispatch_endpoint":null},{"name":"staff.link_user","description":"Link a staff member to a login in this company (one staff member per login); user_id null unlinks. REST: POST /api/v1/staff/{id}/link-user.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/link-user","http_method":"POST","dispatch_endpoint":null},{"name":"staff.list","description":"The people who do the work (the calendar's staff): name, contact, skills, working hours, daily cap, colour, title, employee or contractor, active, and the login each is linked to. Active only unless include_inactive; one kind of worker with employment_status (e.g. contractor). Read-only. REST: GET /api/v1/staff.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","default":false},"employment_status":{"type":"string","nullable":true,"enum":["employee","contractor","temp","intern"]}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/list","http_method":"POST","dispatch_endpoint":null},{"name":"staff.reactivate","description":"Put someone back on the team for booking. REST: POST /api/v1/staff/{id}/reactivate.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/reactivate","http_method":"POST","dispatch_endpoint":null},{"name":"staff.time_off","description":"Mark a staff member off between two times (\"Jake's off Friday\" = start and end that day). Availability stops offering them and bookings refuse them then. Refuses end before start and an overlap with time off they already have. Jobs already assigned in that window come back in conflicts to reassign. REST: POST /api/v1/staff/{id}/time-off.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"start_time":{"type":"string","description":"ISO 8601; a time with no zone is the business's clock; a bare YYYY-MM-DD is that whole day"},"end_time":{"type":"string","description":"ISO 8601; a time with no zone is the business's clock; a bare YYYY-MM-DD is that whole day"},"reason":{"type":"string","maxLength":500,"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id","start_time","end_time"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_range","when":"end_time is not after start_time.","override":null,"code_in_response":true},{"code":"range_too_long","when":"The window is longer than 366 days.","override":null,"code_in_response":true},{"code":"time_off_overlap","when":"It overlaps time off the staff member already has.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/time-off","http_method":"POST","dispatch_endpoint":null},{"name":"staff.time_off_list","description":"A staff member's time off overlapping start–end (default: everything not over yet). Read-only. REST: GET /api/v1/staff/{id}/time-off.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"start":{"type":"string","description":"ISO 8601; a time with no zone is the business's clock; a bare YYYY-MM-DD is that whole day","nullable":true},"end":{"type":"string","description":"ISO 8601; a time with no zone is the business's clock; a bare YYYY-MM-DD is that whole day","nullable":true}},"required":["staff_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/time-off-list","http_method":"POST","dispatch_endpoint":null},{"name":"staff.time_off_remove","description":"Delete one time-off entry. REST: DELETE /api/v1/staff/time-off/{id}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"time_off_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["time_off_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/time-off-remove","http_method":"POST","dispatch_endpoint":null},{"name":"staff.update","description":"Change a staff member's details — only the fields given (name, email, phone, skills, working_hours, default length, daily cap, on call, colour, title, employment_status). Logins are staff.link_user; on/off the team is staff.deactivate / staff.reactivate. REST: PATCH /api/v1/staff/{id}.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","minimum":1},"name":{"type":"string","minLength":1,"maxLength":160,"nullable":true},"email":{"type":"string","format":"email","nullable":true},"phone":{"type":"string","nullable":true},"skills":{"type":"array","items":{"type":"string"},"description":"what they can do, e.g. [\"hvac\", \"water-heater\"]","nullable":true},"working_hours":{"type":"object","description":"weekday → list of [start, end] in 24h HH:MM, the business's clock: {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}. A missing day = no hours recorded; [] = not working that day. {} clears them.","additionalProperties":{"type":"array","items":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2}},"nullable":true},"default_duration_min":{"type":"integer","minimum":5,"maximum":1440,"nullable":true},"capacity_per_day":{"type":"integer","minimum":1,"maximum":200,"nullable":true},"on_call":{"type":"boolean","nullable":true,"description":"on call = bookable at any hour"},"color_index":{"type":"integer","minimum":0,"maximum":63,"nullable":true},"title":{"type":"string","maxLength":120,"nullable":true,"description":"their role, e.g. \"Lead installer\""},"employment_status":{"type":"string","enum":["employee","contractor","temp","intern"],"nullable":true,"description":"how they work for the business. An installer or subcontractor who is one person is \"contractor\"; a subcontracting FIRM is a vendor (vendor.create, is_1099)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"staff","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staff/update","http_method":"POST","dispatch_endpoint":null},{"name":"staff_create","description":"Add someone to the team who can be booked ('add Rosa, she does plumbing'). A staff member is not a login: link an existing login with login_user_id, or, to give them one, run user_invite with the same email afterwards — the login is linked to this person when they accept.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":160},"email":{"type":"string"},"phone":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"working_hours":{"type":"object","description":"weekday → [[start, end], …] in 24h HH:MM, e.g. {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}; {} clears"},"default_duration_min":{"type":"integer","minimum":5,"maximum":1440},"capacity_per_day":{"type":"integer","minimum":1,"maximum":200},"on_call":{"type":"boolean"},"color_index":{"type":"integer","minimum":0,"maximum":63},"title":{"type":"string","maxLength":120},"employment_status":{"type":"string","enum":["employee","contractor","temp","intern"],"description":"an installer or subcontractor who is one person is \"contractor\"; a subcontracting firm is a vendor"},"login_user_id":{"type":"integer","description":"an existing login to link"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_deactivate","description":"Take someone off the team for booking ('Jake left'): never offered or assigned again. Their open jobs are not moved — they come back to reassign. Their login is separate (user_deactivate).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.deactivate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_get","description":"One staff member in full plus their load — open jobs in the next 14 days and time off coming up ('how busy is Jake this week'). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"}},"required":["staff_id"]},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_hours","description":"Set a staff member's weekly working hours (replaces them): 'Rosa works Mon–Fri 8 to 4' → {mon..fri: [[\"08:00\",\"16:00\"]]}. [] = not working that day; {} clears.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"hours":{"type":"object","description":"weekday → [[start, end], …] in 24h HH:MM, e.g. {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}; {} clears"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id","hours"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.hours","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_link_user","description":"Link a staff member to a login in this company, so 'my jobs' means theirs (one staff member per login). Omit login_user_id to unlink.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"login_user_id":{"type":"integer","description":"users.id"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.link_user","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_list","description":"Who's on the team — the people who do the jobs: name, skills, working hours, daily cap, active, and the login each is linked to. 'Who works for us', 'who can do HVAC'. include_inactive adds people taken off the team. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean"},"employment_status":{"type":"string","enum":["employee","contractor","temp","intern"],"description":"only this kind of worker — 'who are our contractors'"}}},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_reactivate","description":"Put someone back on the team for booking.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.reactivate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_time_off","description":"Mark a staff member off ('Jake's off Friday', 'Rosa's out 2–5 today'). They stop being offered and can't be booked then. Jobs already in that window come back to reassign. Refuses an end before the start and time off that overlaps theirs.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"start_time":{"type":"string","description":"ISO 8601; no zone = the business's clock; YYYY-MM-DD = that whole day"},"end_time":{"type":"string","description":"ISO 8601; no zone = the business's clock; YYYY-MM-DD = that whole day"},"reason":{"type":"string","maxLength":500},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id","start_time","end_time"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.time_off","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_time_off_list","description":"A staff member's time off (default: everything not over yet). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"start":{"type":"string","description":"ISO 8601; no zone = the business's clock; YYYY-MM-DD = that whole day"},"end":{"type":"string","description":"ISO 8601; no zone = the business's clock; YYYY-MM-DD = that whole day"}},"required":["staff_id"]},"required_scope":null,"transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.time_off_list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_time_off_remove","description":"Delete one time-off entry (they're working after all).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"time_off_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["time_off_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.time_off_remove","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staff_update","description":"Change a staff member's details — only what you give (name, email, phone, skills, working hours, default job length, daily cap, on call, colour, title, and whether they're an employee or a contractor).","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"staff_id":{"type":"integer","description":"technicians.id (a staff member)"},"name":{"type":"string","minLength":1,"maxLength":160},"email":{"type":"string"},"phone":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"working_hours":{"type":"object","description":"weekday → [[start, end], …] in 24h HH:MM, e.g. {\"mon\": [[\"08:00\", \"17:00\"]], \"sat\": []}; {} clears"},"default_duration_min":{"type":"integer","minimum":5,"maximum":1440},"capacity_per_day":{"type":"integer","minimum":1,"maximum":200},"on_call":{"type":"boolean"},"color_index":{"type":"integer","minimum":0,"maximum":63},"title":{"type":"string","maxLength":120},"employment_status":{"type":"string","enum":["employee","contractor","temp","intern"],"description":"an installer or subcontractor who is one person is \"contractor\"; a subcontracting firm is a vendor"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["staff_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"staff","location":"svc.api","same_as":"staff.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"staging.graduate","description":"Graduate a hosted side app from staging into a real tenant on app.solidnumber.com. Returns a Platform Commerce onboarding URL tagged with the prototype context. When the user finishes checkout, the PC webhook → tenant-provisioning loop runs and provisions a fresh tenant with the app's feature_settings. Reuses the existing /api/v1/demo/{slug}/checkout rail.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":80},"email":{"type":"string","description":"Optional email to prefill in the onboarding wizard.","format":"email","maxLength":254},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"]},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"staging","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staging/graduate","http_method":"POST","dispatch_endpoint":null},{"name":"staging.list","description":"List every side app hosted at staging.solidnumber.com. Returns the slug, name, subdomain, mode (mock / prototype / product), status (alpha / beta / live), and supported platforms (web / ios / android). Use this when a user asks 'what's on staging?' or before deciding which app to graduate.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","description":"Optional filter (e.g. healthcare, scheduling).","maxLength":40},"mode":{"type":"string","enum":["mock","prototype","product"]}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"staging","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staging/list","http_method":"POST","dispatch_endpoint":null},{"name":"staging.open","description":"Return the URL for a side app hosted at staging.solidnumber.com. Use this when a user says 'open Spectrum Care' or asks for a direct link to a hosted app. The CLI side wraps this in a browser-open call; the API just returns the URL.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":80,"description":"The app slug (e.g. spectrum-care)."},"path":{"type":"string","description":"Optional path under the app's root (e.g. /role).","maxLength":256}},"required":["slug"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"staging","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/staging/open","http_method":"POST","dispatch_endpoint":null},{"name":"staging_graduate","description":"Graduate a hosted side app from staging into a real tenant on app.solidnumber.com. Returns a Platform Commerce onboarding URL tagged with the prototype context. When the user finishes checkout, the PC webhook → tenant-provisioning loop runs and provisions a fresh tenant with the app's feature_settings. Reuses the existing /api/v1/demo/{slug}/checkout rail.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":80},"email":{"type":"string","description":"Optional email to prefill in the onboarding wizard.","format":"email","maxLength":254},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["slug"]},"required_scope":"ops:write","transport":"dispatch","coordinate":"09","noun":"staging","location":"svc.api","same_as":"staging.graduate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"checkout_url":{},"name":{},"next_step":{},"slug":{},"tier":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"staging_list","description":"List every side app hosted at staging.solidnumber.com. Returns the slug, name, subdomain, mode (mock / prototype / product), status (alpha / beta / live), and supported platforms (web / ios / android). Use this when a user asks 'what's on staging?' or before deciding which app to graduate.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"category":{"type":"string","description":"Optional filter (e.g. healthcare, scheduling).","maxLength":40},"mode":{"type":"string","enum":["mock","prototype","product"]}}},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"staging","location":"svc.api","same_as":"staging.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"products":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"staging_open","description":"Return the URL for a side app hosted at staging.solidnumber.com. Use this when a user says 'open Spectrum Care' or asks for a direct link to a hosted app. The CLI side wraps this in a browser-open call; the API just returns the URL.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":80,"description":"The app slug (e.g. spectrum-care)."},"path":{"type":"string","description":"Optional path under the app's root (e.g. /role).","maxLength":256}},"required":["slug"]},"required_scope":null,"transport":"dispatch","coordinate":"09","noun":"staging","location":"svc.api","same_as":"staging.open","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"mode":{},"name":{},"slug":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"statement.create","description":"File one period's statement from a processor, gateway or POS/software vendor and its fee lines. Pass intake_id from document.extract on a page it classified `processor_statement` and the period, merchant ID, volume, count and every fee line come off the read; `lines` replaces them. Reports when the lines do not add up to the printed total. Refuses a second statement for the same vendor, merchant and period.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"intake_id":{"type":"integer","minimum":1},"vendor_id":{"type":"integer","minimum":1},"vendor_name":{"type":"string"},"contract_id":{"type":"integer","minimum":1},"period_start":{"type":"string"},"period_end":{"type":"string"},"statement_ref":{"type":"string"},"merchant_id":{"type":"string"},"location":{"type":"string"},"volume":{"type":"number","minimum":0},"transaction_count":{"type":"integer","minimum":0},"total_fees":{"type":"number"},"lines":{"type":"array","items":{"type":"object"},"description":"[{label, amount, fee_type, quantity, basis_amount, rate_bps, page}] — a credit is negative."},"document_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"wrong_document_type","when":"intake_id names a read the OCR classified as something other than a processor statement.","override":null,"code_in_response":true},{"code":"read_already_filed","when":"That read was already filed.","override":null,"code_in_response":true},{"code":"read_has_no_statement","when":"The read carries no statement detail; read the file again with document.extract.","override":null,"code_in_response":true},{"code":"duplicate_statement","when":"A statement for the same vendor, merchant ID and period is already on file.","override":null,"code_in_response":true},{"code":"vendor_mismatch","when":"contract_id belongs to a different vendor.","override":null,"code_in_response":true},{"code":"missing_period","when":"No period_start / period_end was given or read.","override":null,"code_in_response":true},{"code":"missing_lines","when":"The statement has no fee lines.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/create","http_method":"POST","dispatch_endpoint":null},{"name":"statement.evidence","description":"The evidence file for one exception or a whole statement: the charge, the contract term and its words, the amendment chain, the calculation, the review history and the SHA-256 of each original file as read — plus the package's own hash. States facts; draws no legal conclusion.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"exception_id":{"type":"integer","minimum":1},"statement_id":{"type":"integer","minimum":1}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"missing_target","when":"Neither exception_id nor statement_id was given.","override":null,"code_in_response":true}],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/evidence","http_method":"POST","dispatch_endpoint":null},{"name":"statement.exception","description":"One vendor-charge exception with its full calculation: the line, the term and its words, every input, rounding and tolerance.","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"exception_id":{"type":"integer","minimum":1}},"required":["exception_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/exception","http_method":"POST","dispatch_endpoint":null},{"name":"statement.exceptions","description":"Where vendor charges disagreed with the contract, largest first, filtered by status, statement, vendor or class — with the potential overcharge, its annual run-rate, what reviewers confirmed and what came back. Potential means subject to review.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["open","confirmed","rejected","disputed","credited","written_off"]},"statement_id":{"type":"integer","minimum":1},"vendor_id":{"type":"integer","minimum":1},"exception_class":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":500,"default":100}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/exceptions","http_method":"POST","dispatch_endpoint":null},{"name":"statement.get","description":"One vendor statement with every fee line, the fee type each resolves to (and whether a person mapped it), and its exception count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"statement_id":{"type":"integer","minimum":1}},"required":["statement_id"],"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/get","http_method":"POST","dispatch_endpoint":null},{"name":"statement.list","description":"Vendor statements on file, newest period first: vendor, period, merchant ID, volume, total fees, reconciled or not.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"since":{"type":"string"},"until":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":"payments:read","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/list","http_method":"POST","dispatch_endpoint":null},{"name":"statement.map_label","description":"Say what one vendor's fee wording means ('TECH SVC FEE' → technology_fee). Applies to every statement from that vendor, past and future, and overrides the read's guess. Numbers in the label are ignored, so one mapping covers every month.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"label":{"type":"string","minLength":1},"fee_type":{"type":"string","description":"A key of the fee taxonomy (constants/vendor_fee_taxonomy.py), e.g. processor_markup, authorization_fee, pci_compliance_fee, credit."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id","label","fee_type"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_fee_type","when":"fee_type is not a key of constants/vendor_fee_taxonomy.py.","override":null,"code_in_response":true},{"code":"invalid_label","when":"The label is empty once numbers and money punctuation are removed.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/map-label","http_method":"POST","dispatch_endpoint":null},{"name":"statement.reconcile","description":"Check every line of a vendor statement against the APPROVED contract terms, in cents: expected = rate × basis, amount × quantity or amount per period, clamped to min/max; variance = billed − expected. Writes exceptions — rate or fixed-fee variance, fee with no located term, wrong period, wrong merchant ID, duplicate flat fee (also across vendors), missing credit, undercharge, unmapped label — each with the full calculation and the term's words. Re-running keeps decisions a person already made.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"statement_id":{"type":"integer","minimum":1},"tolerance_bps":{"type":"number","minimum":0,"default":50,"description":"Allowed difference as bps of the expected amount."},"tolerance_cents":{"type":"integer","minimum":0,"default":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["statement_id"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/reconcile","http_method":"POST","dispatch_endpoint":null},{"name":"statement.resolve_exception","description":"Record a reviewer's decision on a vendor-charge exception: confirmed, rejected or written_off (both need a note), disputed with the vendor, or credited (with the amount that came back). Records only — moves no money.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"exception_id":{"type":"integer","minimum":1},"status":{"type":"string","enum":["confirmed","rejected","disputed","credited","written_off"]},"note":{"type":"string"},"recovered_amount":{"type":"number","minimum":0},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["exception_id","status"],"additionalProperties":true},"required_scope":"payments:write","transport":"http","coordinate":"524","noun":"vendor_statement","acts_on":{"noun":"vendor_statement","address":"524","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"missing_note","when":"status is rejected or written_off and no note says why.","override":null,"code_in_response":true},{"code":"missing_recovered_amount","when":"status is credited and no recovered_amount was given.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/statement/resolve-exception","http_method":"POST","dispatch_endpoint":null},{"name":"stitch.edit","description":"Edit an existing Stitch screen and return updated layout_json.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string"},"prompt":{"type":"string","minLength":1,"maxLength":4000},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","prompt","screen_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/edit","http_method":"POST","dispatch_endpoint":null},{"name":"stitch.generate","description":"Generate a Stitch design from a text prompt. Returns layout_json sections ready to splice into a WebsitePage.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string"},"project_id":{"type":"string","nullable":true},"device_type":{"type":"string","enum":["DESKTOP","MOBILE","TABLET","AGNOSTIC"],"default":"DESKTOP"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prompt"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/generate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"stitch.import_html","description":"Convert raw HTML into Solid# layout_json via Stitch's block-detection heuristics.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"html":{"type":"string","minLength":1}},"required":["html"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/import-html","http_method":"POST","dispatch_endpoint":null},{"name":"stitch.import_screen","description":"Make an existing Stitch screen a REAL PAGE: fetches it and runs it through nest.import — a preview with an import_id and fidelity score, its images copied into this business's store (Stitch links expire). Then nest.execute.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string","minLength":1},"screen_id":{"type":"string","minLength":1},"options":{"type":"object","nullable":true}},"required":["project_id","screen_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/import-screen","http_method":"POST","dispatch_endpoint":null},{"name":"stitch.projects","description":"Lists the Google Stitch design projects visible to the platform Stitch API key (not tenant-scoped); returns projects and count, or unsupported when Stitch is not configured.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/projects","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"message":{},"ok":{},"projects":{},"reason":{},"scope":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"stitch.screens","description":"Lists the screens inside one Google Stitch project (project_id) via the Stitch API; returns screens and count, or unsupported when Stitch is not configured.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"}},"required":["project_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/screens","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"project_id":{},"reason":{},"screens":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"stitch.status","description":"Whether Stitch (cinematic-block generation backend) is enabled and reachable for the tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"enabled":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"stitch.variants","description":"Generate visual variants of an existing Stitch screen.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"project_id":{"type":"string"},"screen_id":{"type":"string"},"count":{"type":"integer","minimum":1,"maximum":5,"default":3},"prompt":{"type":"string","default":""},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["project_id","screen_id"],"additionalProperties":true},"required_scope":"pages:write","transport":"http","coordinate":"12","noun":"stitch","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/stitch/variants","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"ok":{},"variants":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"storage.delete","description":"Deletes a document from company storage (documents row, by document_id); same record file.delete removes. Only the row is deleted, not the stored object. Returns deleted or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"document_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["document_id"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"87","noun":"storage","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/storage/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"document_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"storage.search","description":"Search this company's stored documents by filename or tag. Runs the real company-scoped query (same predicate as POST /api/v1/storage/search); soft-deleted documents are excluded. A blank query is refused, never answered with an empty list.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":1},"limit":{"type":"integer","minimum":1,"maximum":200,"default":20}},"required":["query"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"87","noun":"storage","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/storage/search","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"query":{},"results":{},"status":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"storage.upload","description":"Upload a document to company storage. Send the bytes base64-encoded in content_base64 (a data: URI is accepted). Malware-scanned and checked against the storage quota before it is stored — the same path as POST /api/v1/storage/upload.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1},"content_base64":{"type":"string","minLength":1},"content_type":{"nullable":true,"type":"string"},"folder_path":{"nullable":true,"type":"string","description":"virtual folder, e.g. Contracts/2026"},"storage_type":{"type":"string","enum":["solid","google_drive","dropbox","onedrive"],"default":"solid"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["content_base64","filename"],"additionalProperties":true},"required_scope":"files:write","transport":"http","coordinate":"87","noun":"storage","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/storage/upload","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"reason":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"subscription.add_seats","description":"Add or remove seats on the subscription. Positive delta_seats adds, negative removes. Pro-rated billing applied immediately if stripe_subscription_id is set. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"delta_seats":{"type":"integer","description":"Number of seats to add (positive) or remove (negative). Must be non-zero."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["delta_seats"]},"required_scope":"billing:write","transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/add-seats","http_method":"POST","dispatch_endpoint":null},{"name":"subscription.cancel","description":"Cancel the subscription at the end of the current period. Customer keeps access until period_end. No refund issued. Reversible up until period_end by calling this verb again with cancel=False. Admin role + typed phrase. NOTE: immediate cancel-with-refund is blocked at the manifest layer (subscription_cancel_immediate) — that path is human-only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cancel":{"type":"boolean","description":"True (default) to schedule cancellation; False to revert a prior cancel."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"billing:write","transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/cancel","http_method":"POST","dispatch_endpoint":null},{"name":"subscription.cancel_policy","description":"What to tell someone who asks to cancel their subscription. An AI is not authorised to cancel — this returns the reason, who can do it, the self-serve page, and a sentence to say. Read-only; cancels nothing.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/cancel-policy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ai_authorized":{},"consider_first":{},"reason":{},"self_serve_url":{},"what_to_say":{},"who_can":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"subscription.downgrade_tier","description":"Schedule a tier downgrade for the next billing period boundary. Customer keeps current tier features until period_end, then drops to the lower tier. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_tier_slug":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to_tier_slug"]},"required_scope":"billing:write","transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/downgrade-tier","http_method":"POST","dispatch_endpoint":null},{"name":"subscription.preview_tier_change","description":"Project the impact of moving the company to a target tier WITHOUT executing — price diff + proration + feature gains/losses + limit changes + warnings.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_tier":{"type":"string","enum":["free","starter","builder","professional","enterprise","agent","developer"]}},"required":["target_tier"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/preview-tier-change","http_method":"POST","dispatch_endpoint":null},{"name":"subscription.upgrade_tier","description":"Move the company to a higher subscription tier, effective immediately (prorated). Admin role + typed phrase. Stripe sync happens as a follow-up if stripe_subscription_id is set.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_tier_slug":{"type":"string","description":"Target tier slug (starter, builder, professional, enterprise)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to_tier_slug"]},"required_scope":"billing:write","transport":"http","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/subscription/upgrade-tier","http_method":"POST","dispatch_endpoint":null},{"name":"subscription_add_seats","description":"Add or remove seats on the subscription. Positive delta_seats adds, negative removes. Pro-rated billing applied immediately if stripe_subscription_id is set. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"delta_seats":{"type":"integer","description":"Number of seats to add (positive) or remove (negative). Must be non-zero."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["delta_seats"]},"required_scope":"billing:write","transport":"dispatch","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"subscription.add_seats","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_seats":{},"delta":{},"delta_seats":{},"new_seats":{},"preflight":{},"previous_seats":{},"status":{},"stripe_synced":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"subscription_cancel","description":"Cancel the subscription at the end of the current period. Customer keeps access until period_end. No refund issued. Reversible up until period_end by calling this verb again with cancel=False. Admin role + typed phrase. NOTE: immediate cancel-with-refund is blocked at the manifest layer (subscription_cancel_immediate) — that path is human-only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"cancel":{"type":"boolean","description":"True (default) to schedule cancellation; False to revert a prior cancel."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"billing:write","transport":"dispatch","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"subscription.cancel","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"cancel_at_period_end":{},"current_tier":{},"effective_at":{},"preflight":{},"status":{},"stripe_synced":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"subscription_downgrade_tier","description":"Schedule a tier downgrade for the next billing period boundary. Customer keeps current tier features until period_end, then drops to the lower tier. Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_tier_slug":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to_tier_slug"]},"required_scope":"billing:write","transport":"dispatch","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"subscription.downgrade_tier","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"effective_at":{},"from_tier":{},"preflight":{},"status":{},"stripe_synced":{},"to_tier":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"subscription_upgrade_tier","description":"Move the company to a higher subscription tier, effective immediately (prorated). Admin role + typed phrase. Stripe sync happens as a follow-up if stripe_subscription_id is set.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"to_tier_slug":{"type":"string","description":"Target tier slug (starter, builder, professional, enterprise)."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["to_tier_slug"]},"required_scope":"billing:write","transport":"dispatch","coordinate":"580","noun":"plan","acts_on":{"noun":"plan","address":"580","domain":"Solid# accounts","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":"subscription.upgrade_tier","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"from_tier":{},"new_price_monthly_cents":{},"preflight":{},"price_monthly_cents":{},"status":{},"stripe_synced":{},"to_tier":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.analyze","description":"AI-analyze survey responses and generate insights.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","minimum":1}},"required":["survey_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ai_unavailable":{},"method":{},"status":{},"survey_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.create","description":"Create a survey from explicit questions. It starts as a draft; survey.publish makes it live.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"questions":{"type":"array","items":{"type":"object"},"minItems":1},"description":{"type":"string","nullable":true},"thank_you_message":{"type":"string","nullable":true},"allow_multiple_responses":{"type":"boolean","default":false},"fields":{"type":"array","items":{"type":"object"},"nullable":true,"description":"Same as questions."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"fields_count":{},"lifecycle":{},"next":{},"status":{},"survey_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.generate","description":"AI-generate a survey from a natural language prompt.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1},"context":{"type":"object","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["prompt"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/generate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.list","description":"Lists the tenant surveys (surveys table), newest first, optionally filtered by status, up to 200. Returns id, title, status, is_active and response_count for each, plus a total.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"surveys":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.optimize","description":"AI-optimize an existing survey for better response rates.","shape":"suggest","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","minimum":1}},"required":["survey_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/optimize","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.publish","description":"Publish a survey — makes it available for responses.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["survey_id"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/publish","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"lifecycle":{},"status":{},"summary":{},"survey_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"survey.set_live","description":"Switch a published form on or off. Off keeps every answer and takes no new ones; a draft answers 'invalid' — publish it first.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","minimum":1},"live":{"type":"boolean"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["survey_id","live"],"additionalProperties":true},"required_scope":"marketing:write","transport":"http","coordinate":"32","noun":"survey","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/survey/set-live","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"lifecycle":{},"status":{},"summary":{},"survey_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"surveys.analyze","description":"AI analysis of survey results - identify patterns and insights","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","description":"Survey ID"}},"required":["survey_id"]},"required_scope":null,"transport":"http","coordinate":"39","noun":"surveys","location":"svc.api","same_as":"survey.analyze","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/surveys/analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ai_unavailable":{},"method":{},"status":{},"survey_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"surveys.create","description":"Alias of survey.create (same handler): create a draft survey in the surveys table from title plus questions (or fields); it stays inactive until survey.publish. Returns survey_id and lifecycle draft.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"title":{"type":"string","description":"Survey title (required)"},"fields":{"type":"array","description":"List of form fields [{id: \"q1\", type: \"text\", label: \"...\", required: true}]"},"description":{"type":"string","description":"Survey description"},"allow_multiple_responses":{"type":"boolean"},"questions":{"type":"array","description":"Same as fields."},"thank_you_message":{"type":"string","description":"Message after submission"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["title"]},"required_scope":"marketing:write","transport":"http","coordinate":"39","noun":"surveys","location":"svc.api","same_as":"survey.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/surveys/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"fields_count":{},"lifecycle":{},"next":{},"status":{},"survey_id":{},"title":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"surveys.get_responses","description":"Get survey responses and basic analytics","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","description":"Survey ID"},"limit":{"type":"integer","description":"Max responses to return (default 100)"}},"required":["survey_id"]},"required_scope":null,"transport":"http","coordinate":"39","noun":"surveys","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/surveys/get-responses","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"responses":{},"showing":{},"survey_id":{},"survey_title":{},"total_responses":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"surveys.list","description":"Alias of survey.list (same handler): read the tenant's surveys table, newest id first, optional status filter and limit up to 200. Returns id, title, status, is_active and response_count per survey.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","description":"Max surveys to return (default 50)"},"status":{"type":"string"}}},"required_scope":null,"transport":"http","coordinate":"39","noun":"surveys","location":"svc.api","same_as":"survey.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/surveys/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"surveys":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"surveys.send","description":"Send survey link to contacts via email campaign","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"survey_id":{"type":"integer","description":"Survey ID to send"},"target_segment":{"type":"string","description":"Who to send to (all, recent_customers, high_value)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["survey_id"]},"required_scope":"marketing:write","transport":"http","coordinate":"39","noun":"surveys","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/surveys/send","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"message":{},"recipients":{},"status":{},"survey_id":{},"survey_title":{},"survey_url":{},"target_segment":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.assign_line","description":"Set a line's owner: company front door / a user's shared human+AI line / an agent's own line. Enforces owner consistency and cross-tenant guards; auto-corrects an invalid routing_mode to the owner default. Pinned lines are refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"owner_type":{"type":"string","enum":["company","user","agent"]},"agent_id":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","owner_type"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"line_pinned","when":"The line is pinned.","override":null,"code_in_response":true},{"code":"invalid_owner","when":"A company or agent owner given with a user_id, or the agent is disabled.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/assign-line","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"assigned":{},"detail":{},"error":{},"line_id":{},"owner_type":{},"phone_number":{},"routing_mode":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.configure_line","description":"Configure a line's behavior through the provision engine: greeting, voicemail, business hours, ring plan (forward_to/ring_strategy/ring_timeout/fallback_action), recording, SMS auto-reply, voice/SMS enablement. Owner (switchboard.assign_line), routing mode (switchboard.set_routing_mode), and the call tree (call_flow.*) have their own verbs and cannot be changed here. Pinned lines are refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"settings":{"type":"object","description":"any of: greeting_message, greetings (a per-scenario map — {\"default\": …, \"after_hours\": …, \"known_caller\": \"Hi {first_name}…\"} — stored in voice_config; falls back known_caller -> after_hours -> default -> greeting_message, and a placeholder that cannot be filled is skipped rather than spoken raw), voicemail_enabled, voicemail_greeting_url, business_hours, forward_to, ring_strategy, ring_timeout, fallback_action, recording_enabled, recording_announcement, recording_announcement_text, sms_auto_reply, sms_keyword_responses, sms_enabled, voice_enabled"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","settings"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"no_configurable_fields","when":"None of the settings is a behaviour field (owner, routing and call tree have their own verbs).","override":null,"code_in_response":true},{"code":"line_pinned","when":"The line is pinned.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/configure-line","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"applied":{},"configured":{},"detail":{},"error":{},"ignored":{},"line_id":{},"phone_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.diagnose","description":"The comms doctor: sweep the whole board and return findings with severity + plain-words message + the fix — degraded email lane, provisioning stuck, TFV rejected/stalled, unhealthy agent bindings, ring/ask modes with no human assigned, silent lines paying rental, a bound phone tree offering a department nobody wired to a number or a person. Healthy board returns findings: []. Read-only.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"612","noun":"comms_health","acts_on":{"noun":"comms_health","address":"612","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/diagnose","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"checked_external_numbers":{},"checked_lines":{},"company_id":{},"findings":{},"healthy":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.get_line","description":"Full routing matrix for ONE phone line: lifecycle status, owner_type, routing_mode, assigned human, agent + binding health, voice config, personality, translate/language, ring plan, business hours. Returns not_found if the line is outside the viewer's scope (no existence leak).","shape":"explain","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1}},"required":["line_id"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/get-line","http_method":"POST","dispatch_endpoint":null},{"name":"switchboard.get_usage","description":"Per-line usage + retail charge for one billing period (default: current month): SMS sent/received, voice minutes and calls in/out, billed flag, and company totals. Privacy-scoped like every Switchboard read.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"period_year":{"type":"integer","nullable":true},"period_month":{"type":"integer","minimum":1,"maximum":12,"nullable":true}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"690","noun":"phone_charges","acts_on":{"noun":"phone_charges","address":"690","domain":"Solid# comms charges","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/get-usage","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"lines":{},"period":{},"totals":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.list_lines","description":"The Switchboard board: every phone line the viewer may see (per-user privacy scope) plus the company's email identity, with effective state computed at read time — lifecycle status (active/pending verification/pending provision/rejected/inactive/released), owner + routing mode, human + agent binding health, voice/personality/language, ring plan, and the email lane truth.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/list-lines","http_method":"POST","dispatch_endpoint":null},{"name":"switchboard.set_routing_mode","description":"Set who answers a line, during its business hours and optionally after them. routing_mode: 'ring' (you first, the AI backs up) | 'ask' (you choose each call — a pop-up on web and phone asks: take it, the AI, or voicemail) | 'ai' (the AI answers; Listen / Take over while it talks) | 'off' (only people, never the AI). after_hours_mode: the same choices for outside the line's hours, or 'same' to clear. ring/ask need a person on the line. Pinned lines are refused. Returns the line's rule in one plain sentence.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"routing_mode":{"type":"string","enum":["ring","ask","ai","off"]},"after_hours_mode":{"type":"string","enum":["ring","ask","ai","off","same"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"line_pinned","when":"The line is pinned.","override":null,"code_in_response":true},{"code":"invalid_routing_mode","when":"ring or ask with no person assigned to the line.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/set-routing-mode","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"line_id":{},"phone_number":{},"routing_mode":{},"updated":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"switchboard.simulate","description":"Dry-run a caller through a line's answer ladder + phone tree WITHOUT dialing: who answers (ring/ask/ai/off + AI backup + binding-health warning) and the decision path the caller's key presses / intents take through the bound call_flow (or the legacy dtmf_actions map, backfilled). Doubles as a flow linter: `flow_errors` for a tree that will not run, and `unreachable_routes` for one that runs but offers a department nobody wired up (the caller gets a message, not a transfer). Powers the Phone Tree builder's test button and `solid call simulate`. Read-only.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","nullable":true},"phone_number":{"type":"string","nullable":true},"inputs":{"type":"array","items":{"type":"string"},"nullable":true,"description":"caller key presses / intents, e.g. [\"1\",\"2\"] or [\"intent:billing\"]"}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"610","noun":"call_flow","acts_on":{"noun":"call_flow","address":"610","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/simulate","http_method":"POST","dispatch_endpoint":null},{"name":"switchboard.verify_line","description":"Submit a toll-free line for carrier verification (TFV) through the provision engine — required before a toll-free number may send SMS. business_info carries the business name/address/contact/use-case fields the carrier requires. Local numbers don't need this. Returns the verification_status (pending/approved). Pinned lines are refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"business_info":{"type":"object","description":"business name, address, contact email/phone, website, use-case category + sample message the carrier requires for toll-free verification"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","business_info"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"line_pinned","when":"The line is pinned.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/switchboard/verify-line","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"line_id":{},"phone_number":{},"submitted":{},"verification_status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"tasks.list_pending","description":"List this company's open CRM tasks (status=pending or in_progress). Sorted by priority then due date. Default top 20. Use when the user asks 'what's on my plate' or 'show my open tasks'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Default 20."},"assigned_to_me":{"type":"boolean","description":"If true, only tasks assigned to the current user."}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"tasks","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/tasks/list-pending","http_method":"POST","dispatch_endpoint":null},{"name":"tasks.needs_you","description":"What needs the OWNER today — the same ranked list their Home screen and the web Daily Brief show, in the same order, with the same wording. Callbacks owed, quotes gone quiet, overdue invoices, anything the engine flagged. Read-only. Use this when the owner asks 'what needs me', 'what should I do today' or 'am I covered'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":20,"description":"How many cards to return. Default 5, the same cap the screens use."}}},"required_scope":null,"transport":"http","coordinate":"99","noun":"tasks","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/tasks/needs-you","http_method":"POST","dispatch_endpoint":null},{"name":"tasks_needs_you","description":"What needs the OWNER today — the same ranked list their Home screen and the web Daily Brief show, in the same order, with the same wording. Callbacks owed, quotes gone quiet, overdue invoices, anything the engine flagged. Read-only. Use this when the owner asks 'what needs me', 'what should I do today' or 'am I covered'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":20,"description":"How many cards to return. Default 5, the same cap the screens use."}}},"required_scope":null,"transport":"dispatch","coordinate":"99","noun":"tasks","location":"svc.api","same_as":"tasks.needs_you","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"company_id":{},"count":{},"needs_you":{},"note":{},"ok":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.block_user","description":"Blocks or unblocks a user in this company by setting users.is_active, which auth enforces on every door; blocking also takes their linked staff row off the calendar and returns their open upcoming jobs (never reassigned). An owner cannot be blocked. Owner or admin only. Requires user_id; returns blocked/unblocked with open_appointments, refused, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"blocked":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"cannot_block_owner","when":"The user is an owner.","override":null,"code_in_response":true},{"code":"cannot_deactivate_self","when":"Blocking yourself.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/block-user","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"is_active":{},"reason":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.deactivate_user","description":"Turn a login off (users.is_active=false; auth refuses it on every door). Not yourself, never the owner; owner or admin only. Reversible with team.reactivate_user. Their linked staff member goes off the calendar too, and their open upcoming jobs come back in open_appointments — never reassigned.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"cannot_deactivate_self","when":"Deactivating yourself.","override":null,"code_in_response":true},{"code":"cannot_deactivate_owner","when":"The user is an owner.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/deactivate-user","http_method":"POST","dispatch_endpoint":null},{"name":"team.invite","description":"Invites a person to this company through the one invite door: validates the role (aliases like employee map to member), checks seats and features, creates a pending user_invitations row and emails the invite link. Owner or admin only. Requires email; returns invitation_id, token, invite_url, expires_at and email_sent, or already_invited / refused with a reason.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","default":"member"},"name":{"type":"string","nullable":true},"assigned_features":{"type":"array","items":{"type":"string"},"nullable":true},"expires_in_days":{"type":"integer","minimum":1,"maximum":30,"default":7},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["email"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"owner_only","when":"Only an owner can invite an owner.","override":null,"code_in_response":true},{"code":"already_member","when":"The email already has access to this company.","override":null,"code_in_response":true},{"code":"already_invited","when":"An unexpired invitation exists; answered with its invitation_id (an expired one is replaced).","override":null,"code_in_response":true},{"code":"seat_limit","when":"The role takes a seat and none are left.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/invite","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"email":{},"expires_at":{},"invitation_id":{},"role":{},"status":{},"token":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.list","description":"The logins on this company's team — email, name, role, active, last login — each with the staff member it is linked to (or null). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_disabled":{"type":"boolean","default":false},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/list","http_method":"POST","dispatch_endpoint":null},{"name":"team.list_invitations","description":"Lists this company team invitations (user_invitations), newest first, optionally filtered by status such as pending. Returns id, email, role, status and name for each, plus a total.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/list-invitations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"invitations":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.reactivate_user","description":"Turn a deactivated login back on (users.is_active=true); owner or admin only. Their staff member comes back on the calendar only if turning the login off is what took them off.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"already_active","when":"The user is already active.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/reactivate-user","http_method":"POST","dispatch_endpoint":null},{"name":"team.revoke_invitation","description":"Deletes a team invitation row (user_invitations) so its link stops working. Requires invitation_id; returns status revoked, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invitation_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invitation_id"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/revoke-invitation","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"invitation_id":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.update_ai_permissions","description":"Update a team member's AI agent permissions.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"permissions":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["permissions"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/update-ai-permissions","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ai_permissions":{},"ignored_unknown_keys":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team.update_role","description":"Changes the role of an existing user in this company (users.role). The role is validated against the canonical roles (aliases like employee map to member) and moving onto a seat role runs the seat check. Owner or admin only. Requires user_id and role; returns old_role and new_role, or not_found / error with a reason.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"role":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["role"],"additionalProperties":true},"required_scope":"team:write","transport":"http","coordinate":"20","noun":"team","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/team/update-role","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"new_role":{},"old_role":{},"status":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team_block_user","description":"Block (blocked=true) or unblock a login — the same switch as user_deactivate / user_reactivate, and idempotent. The owner and yourself can't be blocked. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"blocked":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"20","noun":"team","location":"svc.api","same_as":"team.block_user","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"team_list","description":"List users (logins) on the company team with their roles, last login, and the staff member each login is linked to (the person on the calendar), if any.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_disabled":{"type":"boolean"},"limit":{"type":"integer","minimum":1,"maximum":200}}},"required_scope":null,"transport":"dispatch","coordinate":"20","noun":"team","location":"svc.api","same_as":"team.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"count":{},"users":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"team_list_invitations","description":"Team invitations for this company (who was invited, role, pending / accepted / expired / revoked), newest first; filter by status.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","accepted","expired","revoked"]}}},"required_scope":null,"transport":"dispatch","coordinate":"20","noun":"team","location":"svc.api","same_as":"team.list_invitations","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"team_revoke_invitation","description":"Withdraw a team invitation so its link stops working.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"invitation_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["invitation_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"20","noun":"team","location":"svc.api","same_as":"team.revoke_invitation","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"team_update_ai_permissions","description":"Turn a team member's AI features on or off — permissions is a map of feature key → true/false (the same per-user AI permissions the Users screen sets). Unknown keys are reported back, not applied. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"permissions":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id","permissions"]},"required_scope":"team:write","transport":"dispatch","coordinate":"20","noun":"team","location":"svc.api","same_as":"team.update_ai_permissions","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"teams.send_message","description":"Microsoft Teams — send a channel message. Really sends it via Microsoft Graph. Requires the company to be in Microsoft mode with Microsoft 365 connected. channel accepts '<team_id>/<channel_id>' or a channel display name (pass team_id to narrow the search).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"channel":{"type":"string","minLength":1},"message":{"type":"string","minLength":1},"team_id":{"type":["string","null"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["channel","message"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"26","noun":"teams","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/teams/send-message","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"channel_id":{},"message_id":{},"status":{},"team_id":{},"web_url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"teams.send_notification","description":"Microsoft Teams — send a notification Adaptive Card to a channel. Really sends it via Microsoft Graph. Requires the company to be in Microsoft mode with Microsoft 365 connected. channel accepts '<team_id>/<channel_id>' or a channel display name (pass team_id to narrow the search).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"channel":{"type":"string","minLength":1},"title":{"type":"string","minLength":1},"body":{"type":"string","minLength":1},"team_id":{"type":["string","null"]},"action_url":{"type":["string","null"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["body","channel","title"],"additionalProperties":true},"required_scope":"comms:write","transport":"http","coordinate":"26","noun":"teams","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/teams/send-notification","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"channel_id":{},"message_id":{},"status":{},"team_id":{},"web_url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"thumbtack.connect","description":"Initiate Thumbtack OAuth. Returns OAuth URL.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"93","noun":"thumbtack","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/thumbtack/connect","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"oauth_url":{},"status":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"thumbtack.disconnect","description":"Deactivates the tenant's Thumbtack integration (integrations row, provider thumbtack) by setting is_active false; the row and tokens stay. Returns disconnected or not_connected.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"93","noun":"thumbtack","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/thumbtack/disconnect","http_method":"POST","dispatch_endpoint":null},{"name":"thumbtack.status","description":"Reads the tenant's Thumbtack integration (integrations row, provider thumbtack). Returns connected, active or inactive, integration_id and last_sync_at.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"93","noun":"thumbtack","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/thumbtack/status","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"connected":{},"integration_id":{},"last_sync_at":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"thumbtack.sync_phones","description":"Thumbtack — register the company's Solid# line with its Thumbtack business so leads route through Solid#. Really calls Thumbtack. phone_number is optional and, when given, must match one of the company's own active numbers.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone_number":{"nullable":true,"type":"string","minLength":1,"description":"Optional; must be one of this company's active Solid# numbers."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"93","noun":"thumbtack","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/thumbtack/sync-phones","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"integration_id":{},"phone_number":{},"status":{},"summary":{},"thumbtack_business_id":{},"thumbtack_phone_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"thumbtack.update_settings","description":"Sets fields on the active Thumbtack integrations row; only keys that are existing columns (e.g. config, sync_contacts, sync_interval_minutes) are applied, others ignored. Echoes the settings given.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"settings":{"type":"object"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["settings"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"93","noun":"thumbtack","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/thumbtack/update-settings","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"settings":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"token_swap","description":"Re-tokenize a saved payment method (e.g., processor migration or token expiry). Admin role + typed phrase.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"old_token":{"type":"string"},"contact_id":{"type":"integer"},"processor":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["old_token"]},"required_scope":"payments:write","transport":"dispatch","coordinate":"532","noun":"card_on_file","acts_on":{"noun":"card_on_file","address":"532","domain":"Taking payment","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"card_on_file.swap_token","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"transaction.abort","description":"Seal an open CLI transaction as aborted and reverse its changes: entity_versions tagged with the transaction are restored, and entities it created are deleted. Returns the ops log and reversal counts.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transaction_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/abort","http_method":"POST","dispatch_endpoint":null},{"name":"transaction.append","description":"Append a staged op to an open transaction.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"string"},"verb":{"type":"string"},"payload":{"type":"object","nullable":true},"receipt_id":{"type":"string","nullable":true},"ttl_seconds":{"type":"integer","default":86400,"description":"How long the open transaction survives, in seconds."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transaction_id","verb"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/append","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"op":{},"op_count":{},"status":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"transaction.commit","description":"Seal an open CLI transaction (Redis staging log) as committed so no more ops can be appended; the ops were already applied when run. Returns the transaction_id and its op list.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transaction_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/commit","http_method":"POST","dispatch_endpoint":null},{"name":"transaction.get","description":"Load a transaction's metadata + staged ops.","shape":"transaction","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"string"}},"required":["transaction_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"ops":{},"success":{},"transaction":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"transaction.rollback","description":"Reverse a committed transaction — restores entity state_before for every op in the transaction.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transaction_id":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["transaction_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/rollback","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"failed_reversals":{},"reversed_count":{},"status":{},"success":{},"summary":{},"transaction_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"transaction.start","description":"Open a new CLI transaction: a Redis staging log (default 24h TTL) that groups later mutations under one id for commit or abort. Optional tag and user_id; returns the transaction_id.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tag":{"type":"string","nullable":true},"ttl_seconds":{"type":"integer","minimum":1,"default":86400},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"03","noun":"transaction","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transaction/start","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"error_code":{},"expires_at":{},"status":{},"success":{},"tag":{},"transaction_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"transactions.report","description":"List this company's transactions (orders) for a time window, optionally filtered to declines or refunds. Use this when the user asks to see orders/transactions/sales for a period, or asks about failed, declined, or refunded payments — e.g. 'show me declines this year', 'what failed in the last 90 days', 'how much did we refund YTD'. Returns a count, the summed amount, and the matching rows. Read-only. DECLINES AND REFUNDS ARE DIFFERENT THINGS and this verb keeps them apart: a decline is money that never arrived (the processor refused the charge), a refund is money that arrived and went back. Do not add them together or describe a refund as a failed payment. The window is ALWAYS reported back in `window` — state it when you answer, and never imply a result covers all time. DO NOT fabricate numbers; if count is 0, say so for THAT window and offer a wider one.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"period":{"type":"string","enum":["today","30days","60days","90days","6months","ytd","mtd"],"description":"Time window. Default '30days'. Use 'ytd' for year-to-date and '6months' for the last 180 days."},"status":{"type":"string","enum":["all","declines","refunds"],"description":"'declines' = processor refusals, money that never arrived. 'refunds' = money that arrived and went back, including partial refunds. Default 'all'."},"limit":{"type":"integer","description":"Maximum rows to return. Default 100, max 500.","minimum":1,"maximum":500}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"transactions","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/transactions/report","http_method":"POST","dispatch_endpoint":null},{"name":"ucp.receipts.get","description":"Load a UCP action receipt from Redis by action_id for this tenant. Returns capability, issue time, rollback deadline and status; status reads expired once the rollback window has passed.","shape":"receipt","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"action_id":{"type":"string"}},"required":["action_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"ucp","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ucp/receipts.get","http_method":"POST","dispatch_endpoint":null},{"name":"ucp.receipts.issue","description":"Record a UCP action receipt in Redis for a capability_id, with optional metadata and a rollback window (default 900s). Returns the receipt with its action_id; persisted=false if Redis is down.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"capability_id":{"type":"string"},"metadata":{"type":"object","nullable":true},"rollback_window_seconds":{"type":"integer","minimum":1,"default":900},"ttl_seconds":{"type":"integer","default":86400,"description":"How long the receipt stays retrievable, in seconds."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["capability_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ucp","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ucp/receipts.issue","http_method":"POST","dispatch_endpoint":null},{"name":"ucp.receipts.rollback","description":"Mark a UCP action receipt (Redis, by action_id) as rolled_back within its rollback window, with an optional reason. Records intent only; it does not undo the underlying action. Returns the receipt.","shape":"receipt","side_effects":"mixed","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"action_id":{"type":"string"},"reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["action_id"],"additionalProperties":true},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"ucp","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ucp/receipts.rollback","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"can_rollback_until":{},"error_code":{},"status":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"ucp.recommendations","description":"Suggested capability set for an agent_type + adoption rates.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_type":{"type":"string","enum":["operations","platform","sales","support"]}},"required":["agent_type"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"09","noun":"ucp","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/ucp/recommendations","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_type":{},"company_scope":{},"error_code":{},"known_types":{},"learning_mode":{},"recommendations":{},"success":{},"tenants_observed":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"user.change_role","description":"Change a user's role (owner, admin, manager, member, read_only, sales, marketing, customer_support, accounting, developer; 'employee' means member). Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"new_role":{"type":"string","enum":["owner","admin","manager","developer","sales","marketing","customer_support","accounting","member","read_only","employee"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id","new_role"]},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"user","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/user/change-role","http_method":"POST","dispatch_endpoint":null},{"name":"user.deactivate","description":"Disable login for a user. Reversible — set is_active=true to restore. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"]},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"user","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/user/deactivate","http_method":"POST","dispatch_endpoint":null},{"name":"user.invite","description":"Invite a new user to the company. Creates a pending invitation with a token and sends the invite email. The person accepts by clicking the link and setting their own password — no autonomous account creation. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","manager","developer","sales","marketing","customer_support","accounting","member","read_only","employee"]},"name":{"type":"string","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["email","role"]},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"user","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/user/invite","http_method":"POST","dispatch_endpoint":null},{"name":"user.reactivate","description":"Restore login for a user who was deactivated. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"]},"required_scope":"team:write","transport":"http","coordinate":"29","noun":"user","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/user/reactivate","http_method":"POST","dispatch_endpoint":null},{"name":"user_change_role","description":"Change a user's role (owner, admin, manager, member, read_only, sales, marketing, customer_support, accounting, developer; 'employee' means member). Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"new_role":{"type":"string","enum":["owner","admin","manager","developer","sales","marketing","customer_support","accounting","member","read_only","employee"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id","new_role"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"user","location":"svc.api","same_as":"user.change_role","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_role":{},"new_role":{},"preflight":{},"previous_role":{},"status":{},"target_user_id":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"user_deactivate","description":"Disable login for a user. Reversible — set is_active=true to restore. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"user","location":"svc.api","same_as":"user.deactivate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_active":{},"preflight":{},"status":{},"target_user_id":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"user_invite","description":"Invite a new user to the company. Creates a pending invitation with a token and sends the invite email. The person accepts by clicking the link and setting their own password — no autonomous account creation. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","manager","developer","sales","marketing","customer_support","accounting","member","read_only","employee"]},"name":{"type":"string","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["email","role"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"user","location":"svc.api","same_as":"user.invite","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"email":{},"email_sent":{},"expires_at":{},"invitation_id":{},"invite_url":{},"preflight":{},"role":{},"status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"user_reactivate","description":"Restore login for a user who was deactivated. Owner role only.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"target_user_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["target_user_id"]},"required_scope":"team:write","transport":"dispatch","coordinate":"29","noun":"user","location":"svc.api","same_as":"user.reactivate","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"current_active":{},"preflight":{},"status":{},"target_user_id":{},"user_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.api.endpoint_check","description":"Check one of this API's endpoints with a safe request (GET, HEAD or OPTIONS) as the caller, and report status and latency. Never changes data.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"method":{"type":"string","enum":["GET","HEAD","OPTIONS"],"description":"A safe method — a check never changes data"},"endpoint":{"type":"string","description":"API endpoint path starting with / (e.g., \"/api/v1/contacts\")"},"body":{"type":"object","description":"Ignored; safe methods send no body"},"headers":{"type":"object","description":"Additional headers"},"expected_status":{"type":"integer","description":"List of acceptable status codes (default: [200, 201])"}},"required":["endpoint","method"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/api.endpoint-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.api.latency_check","description":"Check API latency across multiple endpoints.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"endpoints":{"type":"array","description":"List of endpoints to check (uses defaults if None)"},"threshold_ms":{"type":"integer","description":"Latency threshold for \"slow\" classification"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/api.latency-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.api.schema_check","description":"Check if API response contains expected fields.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"endpoint":{"type":"string","description":"API endpoint to check"},"expected_fields":{"type":"array","description":"List of field names that should be in response"}},"required":["endpoint"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/api.schema-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.diagnose.failure","description":"Diagnose why a page or endpoint is failing.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"route":{"type":"string","description":"Frontend route that's failing"},"endpoint":{"type":"string","description":"API endpoint that's failing"}}},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/diagnose.failure","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.journey.run","description":"Run a scripted user journey (signup, dashboard, crm, payment, ai_chat, or custom steps) by loading frontend pages and API endpoints over HTTP; needs ops:validation:read. Returns per-step pass or fail and pass_rate.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"journey_name":{"type":"string","description":"Name of the journey (e.g., \"signup\", \"payment\", \"crm\")"},"steps":{"type":"array","description":"Custom steps to run (uses predefined if None)"}},"required":["journey_name"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/journey.run","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.page.api_check","description":"Check if a page's expected API calls work.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"route":{"type":"string","description":"Page route (for context)"},"expected_apis":{"type":"array","description":"List of API endpoints the page should call"}},"required":["route"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/page.api-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.page.batch_check","description":"Load each frontend route in routes over HTTP and check it responds; needs scope ops:validation:read, optional timeout_ms per page. Returns per-route results and a passed/failed summary with pass_rate.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"routes":{"type":"array","description":"List of page routes to check"},"timeout_ms":{"type":"integer","description":"Max wait time per page"}},"required":["routes"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/page.batch-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.page.check","description":"Check if a page loads successfully (HTTP 200).","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"route":{"type":"string","description":"Page route to check (e.g., \"/dashboard\", \"/auth/v2/login\")"},"timeout_ms":{"type":"integer","description":"Max wait time in milliseconds"}},"required":["route"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/page.check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.page.content_check","description":"Check page content for expected elements and forbidden patterns.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"route":{"type":"string","description":"Page route to check"},"expected_elements":{"type":"array","description":"List of strings that should be in the HTML"},"forbidden_patterns":{"type":"array","description":"List of strings that should NOT be in the HTML"},"timeout_ms":{"type":"integer","description":"Max wait time"}},"required":["route"]},"required_scope":null,"transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/page.content-check","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"error":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"validation.report.generate","description":"Generate a validation report for specified tier or all pages.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"tier":{"type":"integer","description":"1, 2, or 3 (None for all)"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"09","noun":"validation","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/validation/report.generate","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"data":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vendor.archive","description":"Take a vendor off the vendor list (archived=true, the default) or bring it back (archived=false). Never deleted — every purchase keeps it.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"archived":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/archive","http_method":"POST","dispatch_endpoint":null},{"name":"vendor.contacts","description":"The people at a vendor: its main contact and anyone else at the same company in the CRM. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1}},"required":["vendor_id"]},"required_scope":null,"transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/contacts","http_method":"POST","dispatch_endpoint":null},{"name":"vendor.create","description":"Add a vendor — a supplier the business buys from, or (is_1099=true) a subcontractor or contractor FIRM it pays. Refused by name when a vendor with that name already exists (change that one with vendor_update). contact_id makes an existing CRM contact the person behind it. An installer who is ONE person is staff instead (staff_create with employment_status='contractor').","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"tax_id":{"type":"string","description":"EIN / TIN, for 1099s"},"default_category":{"type":"string","description":"materials, fuel, tools, subcontract …"},"payment_terms":{"type":"string","description":"e.g. 'Net 30', 'Due on receipt'"},"is_1099":{"type":"boolean","description":"true for a subcontractor or contractor firm the business pays (1099)"},"notes":{"type":"string"},"contact_id":{"type":"integer","minimum":1,"description":"an existing CRM contact who is the person at this vendor"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"commerce:write","transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"duplicate_vendor","when":"This business already has a vendor with that name (case and spacing ignored); change that one with vendor.update.","override":null,"code_in_response":true},{"code":"contact_not_found","when":"contact_id is not a CRM contact of this business.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/create","http_method":"POST","dispatch_endpoint":null},{"name":"vendor.get","description":"One vendor in full: contact details, payment terms, 1099 flag, active, the person behind it, and what the business has bought from it and still owes it on open bills. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1}},"required":["vendor_id"]},"required_scope":null,"transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/get","http_method":"POST","dispatch_endpoint":null},{"name":"vendor.link_contact","description":"Make a CRM contact the person behind a vendor, and file them as a Vendor. Refused when the vendor already has a different contact (pass replace=true to change it) or the person is already another vendor's contact.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"contact_id":{"type":"integer","minimum":1},"replace":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id","contact_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"vendor_has_contact","when":"The vendor already has a different contact.","override":"replace","code_in_response":true},{"code":"contact_on_another_vendor","when":"That person is already the contact for another vendor.","override":null,"code_in_response":true},{"code":"contact_not_found","when":"contact_id is not a CRM contact of this business.","override":null,"code_in_response":true}],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/link-contact","http_method":"POST","dispatch_endpoint":null},{"name":"vendor.list","description":"Accounts payable — the vendors this business buys from, with contact details, payment terms and 1099 flag.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"search":{"type":"string"},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"items":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vendor.update","description":"Change a vendor's details — only what you give: name, email, phone, address, tax id, default category, payment terms, 1099 flag, notes.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"tax_id":{"type":"string","description":"EIN / TIN, for 1099s"},"default_category":{"type":"string","description":"materials, fuel, tools, subcontract …"},"payment_terms":{"type":"string","description":"e.g. 'Net 30', 'Due on receipt'"},"is_1099":{"type":"boolean","description":"true for a subcontractor or contractor firm the business pays (1099)"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id"]},"required_scope":"commerce:write","transport":"http","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vendor/update","http_method":"POST","dispatch_endpoint":null},{"name":"vendor_archive","description":"Take a vendor off the vendor list (archived=true, the default) or bring it back (archived=false). Never deleted — every purchase keeps it.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"archived":{"type":"boolean","default":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id"]},"required_scope":"commerce:write","transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.archive","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vendor_contacts","description":"The people at a vendor: its main contact and anyone else at the same company in the CRM. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1}},"required":["vendor_id"]},"required_scope":null,"transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.contacts","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vendor_create","description":"Add a vendor — a supplier the business buys from, or (is_1099=true) a subcontractor or contractor FIRM it pays. Refused by name when a vendor with that name already exists (change that one with vendor_update). contact_id makes an existing CRM contact the person behind it. An installer who is ONE person is staff instead (staff_create with employment_status='contractor').","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"tax_id":{"type":"string","description":"EIN / TIN, for 1099s"},"default_category":{"type":"string","description":"materials, fuel, tools, subcontract …"},"payment_terms":{"type":"string","description":"e.g. 'Net 30', 'Due on receipt'"},"is_1099":{"type":"boolean","description":"true for a subcontractor or contractor firm the business pays (1099)"},"notes":{"type":"string"},"contact_id":{"type":"integer","minimum":1,"description":"an existing CRM contact who is the person at this vendor"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name"]},"required_scope":"commerce:write","transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.create","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vendor_get","description":"One vendor in full: contact details, payment terms, 1099 flag, active, the person behind it, and what the business has bought from it and still owes it on open bills. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1}},"required":["vendor_id"]},"required_scope":null,"transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.get","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vendor_link_contact","description":"Make a CRM contact the person behind a vendor, and file them as a Vendor. Refused when the vendor already has a different contact (pass replace=true to change it) or the person is already another vendor's contact.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"contact_id":{"type":"integer","minimum":1},"replace":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id","contact_id"]},"required_scope":"commerce:write","transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.link_contact","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vendor_update","description":"Change a vendor's details — only what you give: name, email, phone, address, tax id, default category, payment terms, 1099 flag, notes.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"vendor_id":{"type":"integer","minimum":1},"name":{"type":"string","minLength":1,"maxLength":255},"email":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"tax_id":{"type":"string","description":"EIN / TIN, for 1099s"},"default_category":{"type":"string","description":"materials, fuel, tools, subcontract …"},"payment_terms":{"type":"string","description":"e.g. 'Net 30', 'Due on receipt'"},"is_1099":{"type":"boolean","description":"true for a subcontractor or contractor firm the business pays (1099)"},"notes":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["vendor_id"]},"required_scope":"commerce:write","transport":"dispatch","coordinate":"520","noun":"vendor","acts_on":{"noun":"vendor","address":"520","domain":"Payables","party":"tenant_vendor","whose":"the business's dealings with the vendors it buys from"},"location":"svc.api","same_as":"vendor.update","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vibe.analyze","description":"Parse a natural-language Vibe prompt and emit a preview_id. Returns the proposed action / entity / cost estimate. Same engine `solid vibe <prompt>` uses.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string"}},"required":["prompt"],"additionalProperties":true},"required_scope":"vibe:execute","transport":"http","coordinate":"74","noun":"vibe","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vibe/analyze","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action":{},"diff_summary":{},"entity_id":{},"entity_type":{},"estimated_cost_usd":{},"ok":{},"preview_id":{},"requires_approval":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vibe.apply","description":"Apply a Vibe preview's changes. Returns history_id for rollback.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"preview_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["preview_id"],"additionalProperties":true},"required_scope":"vibe:execute","transport":"http","coordinate":"74","noun":"vibe","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vibe/apply","http_method":"POST","dispatch_endpoint":null},{"name":"vibe.history","description":"List recent Vibe history entries for the tenant — what was applied, by whom, with rollback ids.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":"vibe:execute","transport":"http","coordinate":"74","noun":"vibe","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vibe/history","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"count":{},"entries":{},"message":{},"ok":{},"reason":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vibe.preview","description":"Fetch the proposed_state + diff_summary for a previously-analyzed Vibe preview.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"preview_id":{"type":"string"}},"required":["preview_id"],"additionalProperties":true},"required_scope":"vibe:execute","transport":"http","coordinate":"74","noun":"vibe","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vibe/preview","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"action":{},"current_state":{},"diff_summary":{},"entity_id":{},"entity_type":{},"ok":{},"preview_id":{},"proposed_state":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vibe.rollback","description":"Roll back a previously-applied Vibe change by history_id.","shape":"revert","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"history_id":{"type":"integer","minimum":1},"reason":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["history_id"],"additionalProperties":true},"required_scope":"vibe:execute","transport":"http","coordinate":"74","noun":"vibe","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/vibe/rollback","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"ok":{},"reason":{},"summary":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"vibe_apply","description":"Apply a previously previewed vibe change to the live site by preview_id (from vibe_preview). Commits the proposed change. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"preview_id":{"type":"string","description":"The preview_id from vibe_preview."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["preview_id"]},"required_scope":"vibe:execute","transport":"dispatch","coordinate":"74","noun":"vibe","location":"svc.api","same_as":"vibe.apply","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"vibe_preview","description":"Propose site changes from a plain-language prompt (e.g. 'make the homepage feel more premium') WITHOUT applying them. Returns a preview_id + a summary of what would change; pass the preview_id to vibe_apply to commit. Uses AI credits.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"description":"What you want changed."}},"required":["prompt"]},"required_scope":"vibe:execute","transport":"dispatch","coordinate":"74","noun":"vibe","location":"svc.api","same_as":"vibe.preview","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch"},{"name":"voice.active_calls","description":"List the company's currently active voice calls (ringing / in_progress / connecting_ai / initiating / queued) with live duration, agent, contact, sentiment, and per-call context, plus the configured concurrency cap.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"professional","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/active-calls","http_method":"POST","dispatch_endpoint":null},{"name":"voice.call_outbound","description":"Call a CRM contact from the right business line. who='ai' (default) dispatches a Solid# agent — same preflight + confirmation + idempotency + audit-log as the dashboard. who='me' calls them as the signed-in person: their cell rings first, then the customer, who sees the business number, never the cell (needs a cell number in call settings — presence.status).","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"intent":{"type":"string","minLength":1,"maxLength":500},"agent_type":{"type":"string","default":"customer_service"},"idempotency_key":{"type":"string","maxLength":64,"nullable":true},"line_id":{"type":"integer","nullable":true,"description":"The business line to call FROM. Omit to use the right line for this person: the line they reached us on, their history, the sales/service line, then the default."},"who":{"type":"string","enum":["ai","me"],"default":"ai"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","intent"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/call-outbound","http_method":"POST","dispatch_endpoint":null},{"name":"voice.console_settings","description":"Read or set the WEB VOICE CONSOLE's transport and engine for this company — no deploy, reaches the next console session. transport: 'auto' (env allowlists decide; the default), 'webrtc' (LiveKit media plane; falls back to the v2 WebSocket when the plane is not configured and says so), 'websocket' (v2 WebSocket, never LiveKit). engine: 'auto' (the requested voice picks the rail; the default), 'openai' (Grok personas run on their OpenAI twin, same name), 'grok' (Grok when plan + xAI key allow, else the OpenAI twin). audio: 'auto' (full-band 24 kHz when the model can carry it; the default), 'full_band', 'narrowband' (µ-law 8 kHz — what a phone caller hears, for an A/B). Call with none to read the current setting and what it resolves to. Stored in companies.business_settings.voice_console; separate from voice.set_engine, which sets an agent's PHONE engine.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"transport":{"type":"string","enum":["auto","webrtc","websocket"]},"engine":{"type":"string","enum":["auto","grok","openai"]},"audio":{"type":"string","enum":["auto","full_band","narrowband"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"611","noun":"voice_engine","acts_on":{"noun":"voice_engine","address":"611","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/console-settings","http_method":"POST","dispatch_endpoint":null},{"name":"voice.end_active_call","description":"End ONE currently-active call now (by call id from voice.active_calls): Twilio tears down every leg, the wall updates immediately. The Live Calls page's End button and an agent's 'hang that call up' are this same verb.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"professional","input_schema":{"type":"object","properties":{"call_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["call_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/end-active-call","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"call_id":{},"detail":{},"error":{},"status":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.list_available_numbers","description":"Search purchasable phone numbers from the carrier — local by area code (optionally matching a pattern) or toll-free. Pure inventory read; nothing is purchased. Follow with voice.provision_number to buy.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"number_type":{"type":"string","enum":["local","toll_free"],"default":"local"},"area_code":{"type":"string","nullable":true,"pattern":"^[0-9]{3}$"},"contains":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":30,"default":10}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/list-available-numbers","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"area_code":{},"error":{},"number_type":{},"results":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.provision_number","description":"BUY a phone number with an owner, end to end: carrier purchase, canonical webhooks, board row with owner_type (company front door | user's shared human+AI line | agent's own line) and the owner's default routing mode, TFV path for toll-free. STARTS A MONTHLY RENTAL. A number already active on any account (pinned lines included) and cross-tenant owners are refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone_number":{"type":"string"},"number_type":{"type":"string","enum":["local","toll_free"],"default":"local"},"owner_type":{"type":"string","enum":["company","user","agent"],"default":"company"},"agent_id":{"type":"integer","nullable":true},"site_id":{"type":"integer","nullable":true},"make_default":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["phone_number"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"invalid_owner","when":"A company or agent owner given with a user_id, or the agent is disabled.","override":null,"code_in_response":true},{"code":"number_already_provisioned","when":"This company already has the number active (error provision_failed).","override":null,"code_in_response":false},{"code":"number_in_use","when":"Another account has the number active (error provision_failed).","override":null,"code_in_response":false}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/provision-number","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"detail":{},"error":{},"line_id":{},"number_type":{},"owner_type":{},"phone_number":{},"provisioned":{},"routing_mode":{},"verification_status":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.release_number","description":"Deactivate a phone line (soft-delete; rental stops next billing run). release_from_twilio=true ALSO releases it at the carrier — PERMANENT and unrecoverable. Pinned lines are refused.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"release_from_twilio":{"type":"boolean","default":false},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[{"code":"line_pinned","when":"The line is pinned.","override":null,"code_in_response":true}],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/release-number","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"carrier_released":{},"detail":{},"error":{},"line_id":{},"phone_number":{},"released":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.send_sms","description":"Dispatch an outbound SMS via an agent. Goes through the same preflight + confirmation + idempotency + audit-log path as the dashboard.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","minimum":1},"body":{"type":"string","minLength":1,"maxLength":1600},"agent_type":{"type":"string","default":"customer_service"},"idempotency_key":{"type":"string","maxLength":64,"nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","body"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"630","noun":"text_message","acts_on":{"noun":"text_message","address":"630","domain":"Texts","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/send-sms","http_method":"POST","dispatch_endpoint":null},{"name":"voice.set_engine","description":"Set an agent's realtime voice engine: provider 'openai' (GPT Realtime, the tuned default) or 'grok' (Grok Voice — Professional+ and the voice-provider-grok flag). Optional model pins a specific engine; omitted uses the provider default. Tier-gated and merged into the agent's voice_config so voice/speed/greeting are preserved. A phone line inherits its bound agent's engine.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"agent_id":{"type":"integer","minimum":1},"provider":{"type":"string","enum":["openai","grok"]},"model":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["agent_id","provider"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"611","noun":"voice_engine","acts_on":{"noun":"voice_engine","address":"611","domain":"Call handling setup","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/set-engine","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_id":{},"detail":{},"effective":{},"error":{},"model":{},"provider":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.set_routing_mode","description":"Set who fields a phone line's inbound contacts: 'ring' (the human first, AI backs up on no-answer), 'ask' (live per-call decision), 'ai' (the agent answers immediately), 'off' (the AI never touches the line). As of 2026-09-09 the answer path HONOURS this — before that every inbound call went to the AI whatever was set here, so changing it changes real call behaviour now. 'ring'/'off' need somebody to ring: a forwarding number or a live softphone (presence.set), else they fall through to voicemail or the AI. Same guard as the web settings page: members may only change their own assigned line; admins any company line.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"line_id":{"type":"integer","minimum":1},"mode":{"type":"string","enum":["ring","ask","ai","off"]},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["line_id","mode"],"additionalProperties":true},"required_scope":"voice:write","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/set-routing-mode","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"line_id":{},"phone_number":{},"previous":{},"routing_mode":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.spend_by_owner","description":"Phone usage & spend per line/user/agent over the trailing months (default 1, max 12): calls, minutes, texts, transcription seconds, and the customer charge per row + total. Customer-facing charges only — wholesale costs are never returned.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"months":{"type":"integer","minimum":1,"maximum":12,"default":1}},"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"690","noun":"phone_charges","acts_on":{"noun":"phone_charges","address":"690","domain":"Solid# comms charges","party":"platform_tenant","whose":"Solid#'s account with the business — not the business's customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/spend-by-owner","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"months":{},"rows":{},"total_charge_cents":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice.translate_status","description":"Live-translation state for a tenant phone line: enabled flag plus supported input/output languages. translate_enabled is true, false, or null when the company has no active line with that number; a null is explained in `unavailable`.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"phone":{"type":"string","pattern":"^\\+?[0-9]{7,15}$"}},"required":["phone"],"additionalProperties":true},"required_scope":"voice:read","transport":"http","coordinate":"600","noun":"phone_line","acts_on":{"noun":"phone_line","address":"600","domain":"Lines & identities","party":"tenant_internal","whose":"the business's own books and settings"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice/translate-status","http_method":"POST","dispatch_endpoint":null},{"name":"voice_call.summary","description":"Fetch the post-call AI summary for a specific voice call. Use when the user asks 'what was that call about' or 'remind me what we discussed with so-and-so'. Returns the summary text + metadata (direction, duration, from_number, to_number, created_at). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer","description":"voice_calls.id"}},"required":["call_id"]},"required_scope":"voice:read","transport":"http","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/voice_call/summary","http_method":"POST","dispatch_endpoint":null},{"name":"voice_call_summary_fetch","description":"Fetch the post-call AI summary for a specific voice call. Use when the user asks 'what was that call about' or 'remind me what we discussed with so-and-so'. Returns the summary text + metadata (direction, duration, from_number, to_number, created_at). Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"call_id":{"type":"integer","description":"voice_calls.id"}},"required":["call_id"]},"required_scope":"voice:read","transport":"dispatch","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"voice_call.summary","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"call_id":{},"created_at":{},"direction":{},"duration_seconds":{},"found":{},"from_number":{},"note":{},"ok":{},"status":{},"summary":{},"to_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"voice_outbound_call","description":"Dispatch a Solid# agent (Sarah for customer service, Marcus for marketing, etc.) to place an outbound voice call to a CRM contact owned by this company. Returns a confirmation card; the call is NOT placed until the user clicks Confirm in the dashboard.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"CRM contact ID owned by this company."},"agent_type":{"type":"string","description":"Which agent should make the call.","enum":["customer_service","marketing","operations","sales","sales_followup"]},"intent":{"type":"string","description":"One-sentence purpose of the call. Passed to the dispatched agent's brief."},"line_id":{"type":"integer","description":"Optional: the business line to call FROM. Omit it and the right line is chosen for this person — the line they reached us on, their site's line, their history, then the sales/service line, then the default."},"call_type":{"type":"string","enum":["transactional","marketing"],"description":"What KIND of call this is. 'transactional' (default) — responsive/expected: a callback the customer asked for, a follow-up on an active job, an emergency call-back. 'marketing' — solicitation/outreach, held to the recipient's 8am-9pm local calling window. Omit for a normal 1:1 callback."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id","intent"]},"required_scope":"voice:write","transport":"dispatch","coordinate":"620","noun":"voice_call","acts_on":{"noun":"voice_call","address":"620","domain":"Calls","party":"tenant_customer","whose":"the business's dealings with its own customers"},"location":"svc.api","same_as":"voice.call_outbound","status":"active","inverse":null,"refuses_when":[],"reversibility":"irreversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"agent_type":{},"audit_id":{},"call_id":{},"contact":{},"contact_id":{},"contact_name":{},"from_line":{},"message":{},"preflight":{},"status":{},"to_number":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook.create","description":"Create a webhook subscription. Returns the signing secret once — it is not shown again.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"},"minItems":1},"description":{"type":"string","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["events","url"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"events":{},"signing_secret":{},"signing_secret_warning":{},"status":{},"subscription_id":{},"summary":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook.delete","description":"Deletes a developer webhook subscription (webhook_subscriptions under the tenant's developer account, by subscription_id). Returns deleted, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["subscription_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/delete","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"subscription_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook.list","description":"Lists developer webhook subscriptions belonging to the tenant's developer account (webhook_subscriptions). Returns id, url, events and is_active per subscription; empty if no developer account.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"subscriptions":{},"total":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook.retry_failed","description":"Retry all failed webhook deliveries for this company over a time window.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":168},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/retry-failed","http_method":"POST","dispatch_endpoint":null},{"name":"webhook.test","description":"Send a signed test payload to a webhook endpoint and report whether it was accepted.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["subscription_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/test","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"delivered":{},"status":{},"subscription_id":{},"summary":{},"url":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook.update","description":"Updates a developer webhook subscription (webhook_subscriptions, by subscription_id): url, events list and/or is_active. Returns status updated, or not_found.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"subscription_id":{"type":"integer","minimum":1},"url":{"type":"string","nullable":true},"events":{"type":"array","items":{"type":"string"},"nullable":true},"is_active":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["subscription_id"],"additionalProperties":true},"required_scope":"integrations:write","transport":"http","coordinate":"94","noun":"webhook","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/webhook/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"subscription_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook_retry_failed","description":"Retry all failed webhook deliveries for this company over a time window.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"since_hours":{"type":"integer","minimum":1,"maximum":168},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"integrations:write","transport":"dispatch","coordinate":"94","noun":"webhook","location":"svc.api","same_as":"webhook.retry_failed","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"capped_at":{},"delivered":{},"preflight":{},"retried":{},"since_hours":{},"status":{},"still_failing":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"webhook_test","description":"Fire a test webhook event to verify a configured webhook URL.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"webhook_id":{"type":"integer"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["webhook_id"]},"required_scope":"integrations:write","transport":"dispatch","coordinate":"94","noun":"webhook","location":"svc.api","same_as":"webhook.test","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"preflight":{},"url":{},"webhook_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"website.generate","description":"Generate (or refresh) this company's multi-page starter website from its knowledge base — homepage, services, about, FAQ, contact and more, with industry-appropriate branding and navigation. Only fills or updates Coming-Soon pages; existing real pages are left intact, so it is safe to re-run. Optionally restrict to a subset of page slugs, set a style preset, or override the industry. Reversible per page. Previews unless confirm=true.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"style":{"type":"string","description":"Optional style preset (e.g. 'modern', 'classic', 'bold')."},"industry":{"type":"string","description":"Optional industry override; defaults to the company's industry."},"pages":{"type":"array","items":{"type":"string"},"description":"Optional subset of page slugs to generate (e.g. ['home', 'services', 'contact']). Defaults to the full set."},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}}},"required_scope":"ops:write","transport":"http","coordinate":"79","noun":"website","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/website/generate","http_method":"POST","dispatch_endpoint":null},{"name":"widget.create_chat","description":"Create a chat widget for the company's website.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string","default":"Default Chat Widget"},"agent_type":{"type":"string","default":"customer_service"},"theme_color":{"type":"string","nullable":true},"welcome_message":{"type":"string","nullable":true},"position":{"type":"string","default":"bottom-right"},"site_id":{"type":"integer","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"additionalProperties":true},"required_scope":"widgets:write","transport":"http","coordinate":"78","noun":"widget","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widget/create-chat","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"agent_type":{},"name":{},"status":{},"widget_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widget.embed_code","description":"Get the embed code snippet for a chat widget.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","minimum":1}},"required":["widget_id"],"additionalProperties":true},"required_scope":"widgets:read","transport":"http","coordinate":"78","noun":"widget","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widget/embed-code","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"chat_id":{},"embed_code":{},"found":{},"status":{},"widget_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widget.update_chat","description":"Edits a website chat widget (chat_widgets, integer id): name, agent personality, greeting, active flag, and theme colour/position merged into its theme. Requires widget_id; returns the fields changed.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"integer","minimum":1},"name":{"type":"string","nullable":true},"agent_type":{"type":"string","nullable":true},"theme_color":{"type":"string","nullable":true},"welcome_message":{"type":"string","nullable":true},"position":{"type":"string","nullable":true},"is_active":{"type":"boolean","nullable":true},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"],"additionalProperties":true},"required_scope":"widgets:write","transport":"http","coordinate":"78","noun":"widget","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widget/update-chat","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"status":{},"updated_fields":{},"widget_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widgets.activate","description":"Sets an embeddable widget in the widgets table (WidgetService, string widget_id, not chat_widgets) to active. Returns the widget_id and status active.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"widgets:write","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/activate","http_method":"POST","dispatch_endpoint":null},{"name":"widgets.clone","description":"Copies a widget in the widgets table (WidgetService, string widget_id) within the tenant, keeping type, config, placement, agents, flow and site; optional new_name. Returns the new widget.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"},"new_name":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"widgets:write","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/clone","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"widget":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widgets.create","description":"Creates an embeddable widget in the widgets table (WidgetService, not chat_widgets) from a name and widget_type, with optional config, placement, agents, flow_id and site_id. Returns the new widget.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"name":{"type":"string"},"widget_type":{"type":"string"},"config":{"type":"object"},"placement":{"type":"object"},"agents":{"type":"array"},"flow_id":{"type":"string"},"site_id":{"type":"integer"},"ai_prompt":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["name","widget_type"]},"required_scope":"widgets:write","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/create","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"widget":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widgets.embed_code","description":"Returns the embed snippet for a widget in the widgets table (WidgetService, string widget_id) in html (default), inline or react format. Read-only.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"},"format":{"type":"string"}},"required":["widget_id"]},"required_scope":"widgets:read","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/embed-code","http_method":"POST","dispatch_endpoint":null},{"name":"widgets.get","description":"Reads one widget from the widgets table (WidgetService, string widget_id, not chat_widgets) for the tenant. Returns the full widget record.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"}},"required":["widget_id"]},"required_scope":"widgets:read","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"widget":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widgets.list","description":"Lists the tenant's widgets from the widgets table (WidgetService, not chat_widgets), filterable by widget_type and status with limit/skip. Returns the widgets and a total count.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_type":{"type":"string"},"status":{"type":"string"},"limit":{"type":"integer"},"skip":{"type":"integer"}}},"required_scope":"widgets:read","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/list","http_method":"POST","dispatch_endpoint":null},{"name":"widgets.metrics","description":"Reads widget analytics from the widgets table: views, interactions, conversions and conversion rate. With widget_id returns one widget; without it returns every widget of the tenant.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"}}},"required_scope":"widgets:read","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/metrics","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"metrics":{},"success":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"widgets.pause","description":"Sets a widget in the widgets table (WidgetService, string widget_id, not chat_widgets) to paused. Returns the widget_id and status paused.","shape":"transaction","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"widgets:write","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/pause","http_method":"POST","dispatch_endpoint":null},{"name":"widgets.update","description":"Update a widget. Pass any field as keyword arg.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"widget_id":{"type":"string"},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["widget_id"]},"required_scope":"widgets:write","transport":"http","coordinate":"79","noun":"widgets","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/widgets/update","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error":{},"success":{},"widget":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow.build","description":"Build a Celery workflow from a natural language description. 'Build me a follow-up email 3 days after every appointment' → deployable workflow.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"description":{"type":"string","minLength":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["description"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/build","http_method":"POST","dispatch_endpoint":null},{"name":"workflow.deploy","description":"Deploy a built workflow — activates it on the Celery beat schedule.","shape":"receipt","side_effects":"write","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["workflow_id"],"additionalProperties":true},"required_scope":"flows:write","transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"degraded","inverse":null,"refuses_when":[],"reversibility":null,"surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/deploy","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"name":{},"status":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow.get","description":"Reads one AI workflow (ai_workflows) by id, including its generated workflow code. Requires workflow_id; returns id, name, description, status (deployed or draft) and workflow_code, or not_found.","shape":"aggregate","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1}},"required":["workflow_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/get","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"description":{},"id":{},"name":{},"status":{},"workflow_code":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow.list","description":"Lists the tenant AI workflows (ai_workflows), newest first; status may be deployed or draft, anything else is an error. Returns id, name, description and status for each, plus a total.","shape":"discovery","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"status":{"type":"string","nullable":true},"limit":{"type":"integer","minimum":1,"maximum":200,"default":50}},"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/list","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"error_code":{},"status":{},"summary":{},"total":{},"workflows":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow.test","description":"Validate a workflow before deployment — checks code integrity and configuration.","shape":"preview","side_effects":"read","surfaces":["cli","http","mcp_stdio","ucp","webmcp"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"workflow_id":{"type":"integer","minimum":1},"test_data":{"type":"object","nullable":true}},"required":["workflow_id"],"additionalProperties":true},"required_scope":null,"transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/test","http_method":"POST","dispatch_endpoint":null,"output_schema":{"type":"object","properties":{"can_deploy":{},"issues":{},"status":{},"workflow_id":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow.trigger","description":"Start a fail-gracefully follow-up chain against a contact: voice call → voicemail → SMS → email → CRM note. The first step fires immediately; subsequent steps are scheduled by the ladder using the company's `follow_up_chain_configs` cascade (per-user → per-agent → company-wide → hardcoded defaults). Pass an explicit `chain_id` to pick a specific workflow from `workflow_list`; omit it to use the company default. Use this when the user says 'follow up with Jane', 'start the no-show recovery on this lead', or 'kick off the post-call drip for #4123'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id of the person to follow up with."},"chain_id":{"type":"integer","description":"Optional follow_up_chain_configs.id. If omitted, the ladder uses the cascade lookup (per-agent, company-wide, defaults)."},"lead_summary":{"type":"string","description":"Short context for the agent's messages — what this follow-up is about (e.g. 'Wanted a quote on a kitchen remodel, didn't pick up'). Max 500 chars.","maxLength":500},"next_goal":{"type":"string","description":"What success looks like for this chain (e.g. 'reschedule the cancelled appointment', 'collect a decision on the proposal'). Max 200 chars.","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"flows:write","transport":"http","coordinate":"08","noun":"workflow","location":"svc.api","same_as":null,"status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"not projected onto this surface; no reason recorded.","webmcp":"not projected onto this surface; no reason recorded.","ucp":"not projected onto this surface; no reason recorded.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":"/api/v1/agent/workflow/trigger","http_method":"POST","dispatch_endpoint":null},{"name":"workflow_list","description":"List the follow-up / automation chains configured for this company. Returns each active chain's id, name, step count, and trigger events. Read-only. Use when the user asks 'what automations do we have' or 'show me my drip chains'.","shape":"discovery","side_effects":"read","surfaces":["cli","http"],"requires_consent":false,"tier_floor":"starter","input_schema":{"type":"object","properties":{"include_inactive":{"type":"boolean","description":"Include is_active=false chains in the response. Default false."}}},"required_scope":null,"transport":"dispatch","coordinate":"08","noun":"workflow","location":"svc.api","same_as":"workflow.list","status":"active","inverse":null,"refuses_when":[],"reversibility":"read","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"chains":{},"company_id":{},"found":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}},{"name":"workflow_trigger","description":"Start a fail-gracefully follow-up chain against a contact: voice call → voicemail → SMS → email → CRM note. The first step fires immediately; subsequent steps are scheduled by the ladder using the company's `follow_up_chain_configs` cascade (per-user → per-agent → company-wide → hardcoded defaults). Pass an explicit `chain_id` to pick a specific workflow from `workflow_list`; omit it to use the company default. Use this when the user says 'follow up with Jane', 'start the no-show recovery on this lead', or 'kick off the post-call drip for #4123'.","shape":"transaction","side_effects":"write","surfaces":["cli","http"],"requires_consent":true,"tier_floor":"starter","input_schema":{"type":"object","properties":{"contact_id":{"type":"integer","description":"crm_contacts.id of the person to follow up with."},"chain_id":{"type":"integer","description":"Optional follow_up_chain_configs.id. If omitted, the ladder uses the cascade lookup (per-agent, company-wide, defaults)."},"lead_summary":{"type":"string","description":"Short context for the agent's messages — what this follow-up is about (e.g. 'Wanted a quote on a kitchen remodel, didn't pick up'). Max 500 chars.","maxLength":500},"next_goal":{"type":"string","description":"What success looks like for this chain (e.g. 'reschedule the cancelled appointment', 'collect a decision on the proposal'). Max 200 chars.","maxLength":200},"confirm":{"type":"boolean","description":"Must be true for this verb to run — it changes something, and without it the call is refused with 400 `confirmation_required`. Pass it only once the person you act for has agreed to this exact action. It is control, not data: it is never handed to the verb."}},"required":["contact_id"]},"required_scope":"flows:write","transport":"dispatch","coordinate":"08","noun":"workflow","location":"svc.api","same_as":"workflow.trigger","status":"active","inverse":null,"refuses_when":[],"reversibility":"reversible","surface_reason":{"mcp_stdio":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","webmcp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","ucp":"flat snake_case name. The stdio bridge routes by dotted name, so these produced 'Unknown tool' phantoms (2026-07-02) and the ADA bridge excludes them deliberately. Reachable over /api/v1/ada/cli-dispatch.","public":"public is an explicit allowlist, not a default — only verbs safe for an unauthenticated reader appear on it."},"http_endpoint":null,"http_method":null,"dispatch_endpoint":"/api/v1/ada/cli-dispatch","output_schema":{"type":"object","properties":{"chain_id":{},"company_id":{},"contact_id":{},"contact_name":{},"conversation_id":{},"current_step":{},"first_step_result":{},"ok":{}},"additionalProperties":true,"description":"Keys inferred from this verb's `return {...}` literals. A strong hint, not a contract: no key is guaranteed present, the list may be incomplete, and value types are unknown.","x-solid-derivation":"inferred-from-return-literals"}}],"retired_addresses":[{"address":"09","was":["0:apply"],"now":[{"address":"512","noun":"customer_credit","title":"Customer credit"}]},{"address":"21","was":["2:compliance"],"now":[{"address":"551","noun":"fee_law","title":"Fee law"}]},{"address":"24","was":["2:presence"],"now":[{"address":"680","noun":"presence","title":"Presence"}]},{"address":"29","was":["2:token"],"now":[{"address":"532","noun":"card_on_file","title":"Card on file"}]},{"address":"36","was":["3:bids"],"now":[{"address":"361","noun":"estimate_draft","title":"AI draft"}]},{"address":"39","was":["3:job","3:proposal","3:proposals"],"now":[{"address":"360","noun":"estimate","title":"Estimate"},{"address":"362","noun":"job","title":"Job"},{"address":"510","noun":"invoice","title":"Invoice"},{"address":"521","noun":"expense","title":"Expense or bill"}]},{"address":"44","was":["4:fee"],"now":[{"address":"552","noun":"account_fee","title":"Account fee"}]},{"address":"48","was":["4:pos"],"now":[{"address":"536","noun":"terminal","title":"Countertop terminal"}]},{"address":"49","was":["4:catalog","4:dispute","4:service","4:vendor"],"now":[{"address":"450","noun":"catalog_item","title":"Catalog item"},{"address":"520","noun":"vendor","title":"Vendor"},{"address":"542","noun":"dispute","title":"Dispute"}]},{"address":"50","was":["5:shift4"],"now":[{"address":"554","noun":null,"title":null}]},{"address":"51","was":["5:payment"],"now":[{"address":"530","noun":"payment","title":"Payment"},{"address":"531","noun":"refund","title":"Refund"},{"address":"532","noun":"card_on_file","title":"Card on file"},{"address":"533","noun":"payment_link","title":"Payment link"},{"address":"562","noun":"affiliate_commission","title":"Affiliate commission"}]},{"address":"52","was":["5:expense"],"now":[{"address":"521","noun":"expense","title":"Expense or bill"}]},{"address":"53","was":["5:invoice"],"now":[{"address":"510","noun":"invoice","title":"Invoice"},{"address":"511","noun":"invoice_payment","title":"Invoice payment"},{"address":"581","noun":"platform_invoice","title":"Solid# invoice"}]},{"address":"54","was":["5:ucp"],"now":[{"address":"09","noun":null,"title":null}]},{"address":"55","was":["5:billing"],"now":[{"address":"581","noun":"platform_invoice","title":"Solid# invoice"},{"address":"583","noun":"platform_payment_method","title":"Card with Solid#"}]},{"address":"56","was":["5:link"],"now":[{"address":"533","noun":"payment_link","title":"Payment link"}]},{"address":"57","was":["5:payments"],"now":[{"address":"531","noun":"refund","title":"Refund"},{"address":"541","noun":"settlement","title":"Settlement"},{"address":"542","noun":"dispute","title":"Dispute"},{"address":"562","noun":"affiliate_commission","title":"Affiliate commission"}]},{"address":"58","was":["5:level3"],"now":[{"address":"553","noun":"interchange","title":"Interchange qualification"}]},{"address":"59","was":["5:accounting","5:bill","5:books","5:charge","5:commission","5:invoices","5:payout","5:revenue","5:subscription"],"now":[{"address":"500","noun":"books","title":"Books"},{"address":"502","noun":"accounting_connection","title":"Accounting connection"},{"address":"510","noun":"invoice","title":"Invoice"},{"address":"511","noun":"invoice_payment","title":"Invoice payment"},{"address":"521","noun":"expense","title":"Expense or bill"},{"address":"541","noun":"settlement","title":"Settlement"},{"address":"562","noun":"affiliate_commission","title":"Affiliate commission"},{"address":"564","noun":"commission_ledger","title":"Commission ledger"},{"address":"580","noun":"plan","title":"Solid# plan"},{"address":"581","noun":"platform_invoice","title":"Solid# invoice"}]},{"address":"60","was":["6:phone"],"now":[{"address":"600","noun":"phone_line","title":"Phone line"},{"address":"601","noun":"external_number","title":"Existing number"},{"address":"620","noun":"voice_call","title":"Call"},{"address":"621","noun":"call_report","title":"Call report"},{"address":"690","noun":"phone_charges","title":"Phone charges"}]},{"address":"61","was":["6:voice"],"now":[{"address":"600","noun":"phone_line","title":"Phone line"},{"address":"611","noun":"voice_engine","title":"Voice engine"},{"address":"620","noun":"voice_call","title":"Call"},{"address":"630","noun":"text_message","title":"Text message"},{"address":"690","noun":"phone_charges","title":"Phone charges"}]},{"address":"62","was":["6:switchboard"],"now":[{"address":"600","noun":"phone_line","title":"Phone line"},{"address":"610","noun":"call_flow","title":"Phone tree"},{"address":"612","noun":"comms_health","title":"Comms health"},{"address":"690","noun":"phone_charges","title":"Phone charges"}]},{"address":"63","was":["6:comms"],"now":[{"address":"671","noun":"comms_workflow","title":"Comms automation"}]},{"address":"64","was":["6:call"],"now":[{"address":"610","noun":"call_flow","title":"Phone tree"},{"address":"620","noun":"voice_call","title":"Call"}]},{"address":"65","was":["6:email"],"now":[{"address":"510","noun":"invoice","title":"Invoice"},{"address":"602","noun":"email_identity","title":"Email identity"},{"address":"640","noun":"email_message","title":"Email"},{"address":"641","noun":"mailbox","title":"Connected mailbox"},{"address":"642","noun":"email_template","title":"Email template"}]},{"address":"66","was":["6:notification"],"now":[{"address":"681","noun":"notification","title":"Notification"}]},{"address":"67","was":["6:communication"],"now":[{"address":"672","noun":"communication_settings","title":"Channel rules"}]},{"address":"68","was":["6:campaign"],"now":[{"address":"670","noun":"email_campaign","title":"Email campaign"}]},{"address":"69","was":["6:calls","6:chat","6:inbox","6:line","6:receipt","6:sms"],"now":[{"address":"600","noun":"phone_line","title":"Phone line"},{"address":"620","noun":"voice_call","title":"Call"},{"address":"630","noun":"text_message","title":"Text message"},{"address":"640","noun":"email_message","title":"Email"},{"address":"650","noun":"chat_conversation","title":"Website chat"},{"address":"651","noun":"chat_widget","title":"Chat widget"},{"address":"660","noun":"inbox_thread","title":"Inbox thread"}]},{"address":"99","was":["9:issue","9:promoter"],"now":[{"address":"531","noun":"refund","title":"Refund"},{"address":"560","noun":"promoter","title":"Promoter"}]}],"etag":"W/\"80954aa85a545c50cc72\""}