Tool catalog #
Classification: Restricted (describes source code, infrastructure, and access control).
Generated file — do not hand-edit. Regenerate with
mise run mcp-tools-doc-genafter adding, renaming or removing a tool inlibs/typescript/mcp-tool/src/tool-groups/. A test fails when this file drifts from the catalog.
Every stable tool in the catalog (138 tools), grouped by category. A tool is only served when apps/tofu-external-mcp registers it for the caller’s environment and agent. read tools change nothing; write tools change data and need the matching BonsAI permission. “destructive hint” is the catalog’s destructiveHint annotation, not a guarantee. For input/output details of the most-used tools see the Tools guide.
Document #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
download_document_file |
read | GET /api/v1/documents/{documentId}/download |
Download the original uploaded document file (e.g. the source PDF or image) as inline bytes, scoped to the given entity. The response is a binary stream (Content-Type set by the file’s media type). |
get_document |
read | GET /api/v1/documents/{documentId} |
Fetch a single document’s data (status, extraction types, metadata) by its id, scoped to the given entity. Does not include the raw file bytes — use download_document_file for that. Requires DocumentUpload:Read permission. |
get_document_metadata |
read | GET /api/v1/documents/{documentId}/metadata |
Fetch a document’s ingestion-source-specific metadata (e.g. inbound-email headers, integration/trigger-sync origin details), scoped to the given entity. Distinct from get_document, which covers status/extraction/page data but not source metadata. Requires DocumentUpload:Read permission. |
get_document_page |
read | GET /api/v1/document-pages/{documentPageId} |
Fetch a single document page’s data (type, page number, rotation, bounding box, public_metadata, is_linked, etc.), scoped to the given entity. Requires DocumentUpload:Read permission. |
get_document_page_image |
read | GET /api/v1/document-pages/{documentPageId}/download |
Fetch a document page’s rendered image as inline bytes, scoped to the given entity. The response is a binary stream (Content-Type image/png). Requires DocumentUpload:Read permission. |
get_document_page_signed_urls |
read | GET /api/v1/document-pages/{documentPageId}/signed-urls |
Get short-lived, signed CDN URLs (one per size: xs/sm/md/lg/xl) for a single document page, valid for a few minutes. Requests beyond the TTL get a fresh URL. Requires DocumentUpload:Read permission. |
get_stale_documents |
read | GET /api/v1/documents/stale |
List documents that are stale — older than 2 months and not yet DONE — for an entity. Paginated (n_per_page 1-100, default 20; page_number, default 0). Useful for finding documents stuck in processing/review that may need cleanup or a reprocess. Requires DocumentUpload:Read permission. |
list_documents |
read | GET /api/v1/documents |
List documents for an entity, filtered only by upload/update time — there is no filter by extraction type, status, etc. Sorted by creation date (newest first). Requires DocumentUpload:Read permission. |
patch_document_page |
write (destructive hint) | PATCH /api/v1/document-pages/{documentPageId} |
Partially update a document page — only the fields provided are changed (at least one of name, rotation, public_metadata, is_multi_snippet is required). Every field replaces its existing value outright except public_metadata, whose keys are deep-merged into the existing object instead of replacing it wholesale. Requires DocumentUpload:Write permission. |
reprocess_document |
write (destructive hint) | POST /api/v1/documents/{documentId}/reprocess |
Re-run the conversion pipeline for a document that failed before producing any pages (e.g. the virus scanner was unavailable) — moves it back to PENDING and re-queues it. Only eligible if the document is in ERROR with no pages and error_type is UNEXPECTED or unset; failures describing a fixed property of the file itself (MALICIOUS, PASSWORD_PROTECTED, EMPTY_FILE, INVALID_FILE, UNSUPPORTED_FILE, TOO_MANY_PAGES) are rejected with a 400 since reprocessing would reach the same verdict. If the document has a source extraction type, extraction re-runs automatically when quota allows — the original upload was already counted against usage, so this never charges twice; with no quota left the document lands in a limit-reached state instead of extracting. Requires DocumentUpload:Write permission. |
update_document |
write (destructive hint) | PATCH /api/v1/documents/{documentId} |
Update a document’s status directly (one of PENDING/PROCESSING/NEEDS_REVIEW/DONE/ERROR), scoped to the given entity. status is required — this endpoint has no other updatable fields. Requires DocumentUpload:Write permission. |
upload_document |
write (destructive hint) | POST /api/v1/documents |
Upload one or more document files (e.g. an invoice and its supporting attachments) as multipart/form-data. All files are added to one document record and will be extracted together as a multi-page document. Requires DocumentUpload:Write permission. |
upsert_document_page |
write (destructive hint) | PUT /api/v1/document-pages |
Update a document page if id is provided and already exists, or create a new one otherwise (omit id to have bonsapi assign one). Rejects (400) creating a new page with type PAGE (only SNIPPET pages can be created this way), a SNIPPET missing its bounding box or original_document_page_id, a PAGE with a bounding box set, or any attempt to change an existing page’s type/entity_id/document_id. Requires DocumentUpload:Write permission. |
Invoice #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_invoice_data |
write (destructive hint) | POST /api/v1/invoices/{invoiceId}/data |
Append a new invoice_data version to an invoice’s history (e.g. an edit). Set is_placeholder true to skip syncing this version to the connected accounting software. Requires EntityExtractions:Write permission. |
get_invoice |
read | GET /api/v1/invoices/{invoiceId} |
Fetch a single invoice (status, publish/import state, and its current invoice_data version, which is the live published/imported version), scoped to the entity. Invoices are created only during extraction processing (no separate create_invoice endpoint). Requires EntityExtractions:Read permission. |
get_invoice_data |
read | GET /api/v1/invoices/{invoiceId}/data |
List the version history of an invoice’s invoice_data (each edit/publish/import/verification event creates a new version). Returns all versions, each with extracted data (amount, date, vendor, etc.) and metadata (who/when). Requires EntityExtractions:Read permission. |
import_invoice |
write (destructive hint) | POST /api/v1/invoices/{invoiceId}/import |
Sync the invoice’s data and attachments in from the connected accounting software (the reverse direction of publish). Requires EntityExtractions:Write permission. |
publish_invoice |
write (destructive hint) | POST /api/v1/invoices/{invoiceId}/publish |
Publish the invoice’s current data and attachments to the connected accounting software (create-only — republishing an already-published invoice is not this call’s job). Requires EntityExtractions:Write permission. |
search_invoice_data |
read | POST /api/v1/invoices/search-data |
Batch-fetch up to 50 invoices at once by the id of a specific invoice_data version — useful when you have a batch of invoice_data ids and want to fetch all their extracted data in one call. Requires EntityExtractions:Read permission. |
Direct expense #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_direct_expense |
write (destructive hint) | POST /api/v1/direct-expenses |
Create a new direct expense with an extraction, scoped to the entity. Requires EntityDirectExpenses:Manage permission. |
create_direct_expense_data |
write (destructive hint) | POST /api/v1/direct-expenses/{directExpenseId}/data |
Create a new version of a direct expense’s data with line items. Requires EntityDirectExpenses:Manage permission. |
delete_direct_expense |
write (destructive hint) | DELETE /api/v1/direct-expenses/{directExpenseId} |
Soft-delete a direct expense by its id, scoped to the entity. Returns no content on success (204). Requires EntityDirectExpenses:Manage permission. |
get_direct_expense_by_extraction |
read | GET /api/v1/direct-expenses/{extractionId} |
Fetch a single direct expense (status, publish/import state, and its current direct_expense_data version, which is the live published/imported version). Direct expenses are created only during extraction processing (no separate create_direct_expense endpoint). Requires EntityExtractions:Read permission. |
get_direct_expense_data |
read | GET /api/v1/direct-expenses/{directExpenseId}/data |
List the version history of a direct expense’s data (each edit/publish/import/verification event creates a new version). Returns all versions, each with extracted data (amount, date, category, etc.) and metadata (who/when). Requires EntityExtractions:Read permission. |
import_direct_expense |
write (destructive hint) | POST /api/v1/direct-expenses/{directExpenseId}/import |
Sync the direct expense’s data and attachments in from the connected accounting software. Requires EntityDirectExpenses:Create permission. |
list_direct_expenses |
read | GET /api/v1/direct-expenses |
List direct expenses for an entity — pagination only (n_per_page/page_number). Requires EntityDirectExpenses:Read permission. |
publish_direct_expense |
write (destructive hint) | POST /api/v1/direct-expenses/{directExpenseId}/publish |
Publish the direct expense’s current data and attachments to the connected accounting software. Requires EntityDirectExpenses:Update permission. |
search_direct_expense_data |
read | POST /api/v1/direct-expenses/search-data |
Batch-fetch direct expenses by the id of a specific direct_expense_data version — useful when you have a batch of direct_expense_data ids and want to fetch all their extracted data in one call. Requires EntityDirectExpenses:Read permission. |
Extraction #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
confirm_classification |
write | POST /api/v1/extractions/classifications |
Confirm the AI-classified page types for one or more extractions currently held in CLASSIFY_AND_REVIEW mode and enqueue their extraction jobs. Collection-style — a single confirmation is a one-element list; duplicate ids are deduplicated. Ids that are unknown, not awaiting confirmation, missing a primary page, or blocked by the billing limit are returned in the response’s skipped list with a reason instead of failing the whole batch. Requires EntityExtractions:Write permission. |
create_extraction |
write (destructive hint) | POST /api/v1/extractions |
Create a brand-new extraction from already-uploaded document pages AND immediately trigger its processing in the background — a wrapper around create + trigger combined. Requires DocumentUpload:Read and EntityExtractions:Write permissions. Returns the created extraction and its status (DRAFT). |
create_extraction_page |
write (destructive hint) | POST /api/v1/extractions/{extractionId}/pages |
Add a single document page to an existing extraction — creates the extraction-page mapping (document_page_id, its role PRIMARY/SUPPORTING, and its display order). To replace the entire page set at once, use replace_extraction_pages instead. Requires EntityExtractions:Write permission. |
create_soybean |
write (destructive hint) | POST /api/v1/extractions/{extractionId}/soybean |
Trigger an AIOps Hub data-collection job for an extraction — PII masking, extraction-data snapshotting, and related AIOps tasks. Runs asynchronously; this call only queues the job and returns immediately. The extraction should be VERIFIED for the job to process meaningful data. Optionally carries flag metadata (label, reason, reporter_org_role, reporter_initial) recorded as an extraction issue when a tofu member is flagging a problematic extraction. Requires EntityExtractions:Write permission. |
delete_extraction |
write (destructive hint) | DELETE /api/v1/extractions/{extractionId} |
Permanently delete an extraction, scoped to the entity. Returns no content on success (204). Requires EntityExtractions:Write permission. |
delete_extraction_page |
write (destructive hint) | DELETE /api/v1/extractions/{extractionId}/pages/{documentPageId} |
Remove a single page from an extraction by deleting its extraction-page mapping — this does not delete the underlying document page or its data, just this extraction’s link to it. Requires EntityExtractions:Write permission. |
get_extraction |
read | GET /api/v1/extractions/{extractionId} |
Fetch one extraction in full (the shared model across invoices, direct expenses and bank statements), scoped to the entity. This is how you read what was extracted from a document: the response carries the extracted data itself — the invoice number, the counterparty, the dates, the currency, the total, the line items — alongside the title, the pages, the status (DRAFT/PROCESSING/READY), any error, and which version of the data is current (published/imported/verified). list_extractions returns the status-level rows without that data, so it is the wrong tool for reading values: take an id from it and come here. Requires EntityExtractions:Read permission. |
get_stale_extractions |
read | GET /api/v1/extractions/stale |
List stale extractions for an entity — extractions older than 2 months that are still not done. Pagination only (n_per_page/page_number). Requires EntityExtractions:Read permission. |
list_extractions |
read | GET /api/v1/extractions |
List extractions for an entity: the status-level rows only, without the extracted field values — use get_extraction with an id from here to read those. (The shared status model across invoices, direct expenses, and bank statements.) Supports filtering by types, statuses, timestamp_from/timestamp_to (date range, max 3 months, defaults to last month), and updated_after, plus pagination (n_per_page/page_number). When listing drafts, include both DRAFT and legacy NEEDS_REVIEW statuses. Sorted by creation date (newest first). Requires EntityExtractions:Read permission. |
replace_extraction_pages |
write (destructive hint) | PUT /api/v1/extractions/{extractionId}/pages |
Replace the full set of pages on an extraction in one call — every existing extraction-page mapping for this extraction is overwritten with the pages provided. Returns the new set of extraction pages. Requires EntityExtractions:Write permission. |
switch_extraction_type |
write (destructive hint) | POST /api/v1/extractions/{extractionId}/switch-type |
Switch an extraction from one type to another (e.g. AP_BILL to AR_INVOICE): marks the original extraction DELETED and creates a new extraction with the same pages under the target type, returning the newly created extraction. If the original extraction had synced to an external accounting integration, that deletion is synced too — if that sync fails, this call still succeeds but the response’s warning_message reports it. Fails if target_type equals the extraction’s current type, or if the target type isn’t enabled for this entity. Requires EntityExtractions:Write permission. |
trigger_extraction |
write (destructive hint) | PATCH /api/v1/extractions/{extractionId} |
Trigger (or re-trigger) processing on an extraction that already exists, regardless of its current status — not DRAFT-only; bonsapi accepts most statuses (including NEEDS_REVIEW) and only rejects a few specific ones (e.g. VERIFIED must be unverified first; a deleted extraction cannot be re-triggered; an already-PROCESSING extraction is a same-status no-op, not an error). After triggering, the extraction moves to PROCESSING; when background work completes, it moves to READY (or ERROR if something failed). Requires EntityExtractions:Write permission. |
Bank statement #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_bank_statement |
write (destructive hint) | POST /api/v1/bank-statements |
Create a new bank statement with pending extraction status, scoped to the entity. Requires EntityExtractions:Write permission. No v2 equivalent exists — this is create-only regardless of statement version. |
delete_bank_statement |
write (destructive hint) | DELETE /api/v1/bank-statements/{bankStatementId} |
Delete a bank statement by its id, scoped to the entity. Returns no content on success (204). No v2 equivalent exists. Requires EntityExtractions:Write permission. |
get_bank_statement |
read | GET /api/v2/bank-statements/{extractionId} |
Fetch a single bank statement by its extraction id (bank statements have a 1:1 relationship with extractions, like invoices and direct expenses). Bank statements are created only during extraction processing (no separate create_bank_statement endpoint). Requires EntityExtractions:Read permission. |
get_bank_statement_data_activities |
read | GET /api/v1/bank-statements/{bankStatementId}/data/activities |
Get the activity history for a bank statement’s data, scoped to the entity. No v2 equivalent exists. Requires EntityExtractions:Read permission. |
list_bank_statements |
read | GET /api/v1/bank-statements |
List bank statements for an entity — pagination only (n_per_page/page_number); there is no filtering by date/status/etc. Sorted by creation date (newest first). Requires EntityExtractions:Read permission. |
publish_bank_statement |
write (destructive hint) | POST /api/v2/bank-statements/{bankStatementId}/publish |
Publish every account group of a verified v2 (multi-account) bank statement to the connected accounting software’s bank feed in a single batch, returning a per-group result (the v1 single-account endpoint is superseded by this one). Already-published groups are skipped; groups failing local validation are excluded and marked. 4xx is reserved for whole-statement precondition failures (not verified, integration unavailable, or not a v2 statement) — otherwise 200 is returned even for partial or all-failed outcomes. Requires EntityExtractions:Write permission. |
search_bank_statement_data |
read | POST /api/v1/bank-statements/search-data |
Batch-fetch bank statements by the id of a specific bank_statement_data version — useful when you have a batch of bank_statement_data ids and want to fetch all their extracted data in one call. No v2 equivalent exists. Requires EntityExtractions:Read permission. |
upsert_bank_statement_data |
write (destructive hint) | POST /api/v2/bank-statements/{bankStatementId}/data |
Persist the multi-account data list into a bank statement’s data and transactions (v2, multi-account model — the v1 single-account endpoint is superseded by this one). Requires EntityExtractions:Write permission. |
Entity #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
add_entity_member |
write (destructive hint) | POST /api/v1/entities/{entityId}/members |
Add an existing organization member to an entity with a specific role. Requires the caller to hold the entity’s Member:Write permission — checked by bonsapi before the member is added; a caller without it (e.g. the built-in Viewer role) gets a clean permission-denied error. app_user_id is the target’s Clerk external user id (the organization member’s own id, NOT the entity-membership id that update_entity_member/remove_entity_member take) — bonsapi looks the member up by their live Clerk membership in the caller’s organization, so app_user_id must belong to someone who is already an organization member, not merely any UUID. Fails with a clean 400 if they’re already a member of this entity. |
create_entity |
write (destructive hint) | POST /api/v1/entities |
Create a new entity in the caller organization. Requires the caller to hold the Organization:Admin role — members with lower roles (e.g. Entity Admin, Member) get a clean permission-denied error. Returns the created entity, including the caller’s own role in it (always Manager). |
create_entity_knowledge |
write (destructive hint) | POST /api/v1/entities/{entityId}/knowledge |
Kick off knowledge learning for an entity, either from free-form text content or — with contents omitted — from its historical extraction data, which nothing else does. Returns as soon as the job is queued, so the knowledge is not there yet; poll list_knowledge to see the cards appear. Writes whichever knowledge version the entity is on, so its output is what list_knowledge returns. Supports one or more extraction_types (processed sequentially) — pass extraction_types over the deprecated singular extraction_type. Unlike create_knowledge, which writes one card synchronously, this learns a whole set. Requires entity-level entity-knowledge create permission. |
delete_entity |
write (destructive hint) | DELETE /api/v1/entities/{entityId} |
Delete an entity. Returns no content on success (204). Requires the caller to hold the entity’s (or organization’s) entity-delete permission. |
get_entity |
read | GET /api/v1/entities/{entityId} |
Fetch a single entity’s data (name, slug, organization, the caller’s own role, and when it was created/updated), scoped to the entity. Does not return members list — use list_entities for that context. Requires Read permission on the entity (not just membership). |
list_entities |
read | GET /api/v1/entities |
List every entity the caller can access, each with the caller’s own role in it (not roles of other members). Sorted by creation date (oldest first). Paginated via page_number/n_per_page (defaults to 20 per page, max 100). |
list_entity_members |
read | GET /api/v1/entities/{entityId}/members |
List members of an entity, including their roles and permissions — pagination only (n_per_page/page_number). |
remove_entity_member |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/members/{appUserId} |
Remove a member from an entity by deleting their role assignment — they keep their organization membership (they can rejoin the entity later). Requires the caller to hold the entity’s Member:Write permission. Fails with a clean 400 if the member is not in the entity. |
update_entity_member |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/members/{appUserId} |
Change an existing entity member’s role. Requires the caller to hold the entity’s Member:Write permission. The member must already be in the entity — use add_entity_member to add new members. Fails with a clean 400 if the member is not in the entity. |
update_entity_settings |
write (destructive hint) | PATCH /api/v1/entities/{entityId} |
Update an entity’s name, slug, or write-flow settings (auto-publish/import for AI extraction data when processing completes). At least one field is required in the body. Requires the caller to hold the entity’s Admin role. |
Integration setup #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
check_integration_connection |
write | POST /api/v1/integrations/{integrationId}/check-connection |
Call a lightweight accounting-provider API endpoint once to verify whether the integration is currently available or rate limited. Disabled in production (403). Requires EntityIntegrations:Write permission. |
get_integration |
read | GET /api/v1/integrations/{integrationId} |
Fetch a single entity integration (accounting connection like Xero/QuickBooks, or trigger-sync integration like Sharepoint). Returns status, installation warnings, and connection metadata. Requires EntityIntegrations:Read permission. |
get_integration_details |
read | GET /api/v1/integrations/{integrationId}/details |
Fetch an entity integration’s installation_warnings only (each a key/tooltip_key pair). A new/reinstalled integration may have warnings; resolving them ensures triggering data is safe (e.g. Sharepoint folder found). Requires EntityIntegrations:Read permission. |
get_integration_oauth_authorize_url |
write | POST /api/v1/integrations/oauth/authorize |
Get the OAuth authorization URL for a provider (XERO, QUICK_BOOKS, FREEE, MYOB, MONEY_FORWARD, SHAREPOINT, GOOGLE_DRIVE, DROPBOX) instead of being redirected — useful for frontends that need to avoid CORS issues with redirects. redirect_url is where the OAuth flow returns to afterward. |
list_integrations |
read | GET /api/v1/integrations |
List every integration (accounting connections like Xero/QuickBooks, and trigger-sync integrations like Sharepoint) for an entity. Sorted by creation date (newest first). Requires EntityIntegrations:Read permission. |
setup_integration |
write (destructive hint) | PUT /api/v1/integrations/{integrationId} |
Set up or update an existing integration — e.g. choose which Xero organization/tenant or QuickBooks company to use, set Sharepoint/Google Drive/Dropbox source and sub-source and directories, or activate a PENDING WhatsApp integration by setting status to ACTIVE. public_metadata is a discriminated union keyed by provider — see get_integration for the current shape before replacing it, since fields you omit are not preserved from the existing value. Requires EntityIntegrations:Write permission. |
Integration trigger #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
activate_integration_submitter |
write | POST /api/v1/integrations/{integrationId}/submitters/{submitterId}/activate |
Reactivate a previously deactivated WhatsApp submitter — no new OTP or messages are sent, this is purely an admin trust signal. Only valid from DEACTIVATED status; other states return 409. Requires EntityIntegrations:Write permission. |
add_integration_submitter |
write (destructive hint) | POST /api/v1/integrations/{integrationId}/submitters |
Invite a submitter to a WhatsApp integration: generates a verification code, creates an INVITED submitter row, and emails the code. phone_number must be E.164-parseable; first_name/last_name/email are trimmed 1..N chars. By default each phone number can only link to one integration — set multi_entity true to allow linking to more, as long as all links stay within the same organization (cross-organization is always rejected, 422, regardless of multi_entity). Fails 409 if the phone is already linked to this integration, 422 if it is linked elsewhere without multi_entity or in another organization, and 400 if the target integration is not WhatsApp. Requires EntityIntegrations:Write permission. |
deactivate_integration_submitter |
write | POST /api/v1/integrations/{integrationId}/submitters/{submitterId}/deactivate |
Soft-disable a verified WhatsApp submitter — the row is preserved and can later be re-enabled via activate_integration_submitter. Only valid from ACTIVE status; other states return 409. Requires EntityIntegrations:Write permission. |
delete_integration_submitter |
write (destructive hint) | DELETE /api/v1/integrations/{integrationId}/submitters/{submitterId} |
Hard-delete a WhatsApp submitter’s entity-integration link — valid from any status (INVITED/ACTIVE/DEACTIVATED), no state guard. Returns no content on success (204). Requires EntityIntegrations:Write permission. |
get_integration_trigger_sources |
read | GET /api/v1/integrations/{integrationId}/trigger-sources |
List the trigger sources available for a trigger-sync integration (e.g. sites in Sharepoint) — used to pick a source_id when calling setup_integration. Requires EntityIntegrations:Read permission. |
get_integration_trigger_sub_sources |
read | GET /api/v1/integrations/{integrationId}/trigger-sources/{sourceId}/sub-sources |
List the sub-sources under a given trigger source (e.g. document libraries under a Sharepoint site) — used to pick a sub_source_id when calling setup_integration. Requires EntityIntegrations:Read permission. |
list_integration_submitter_logs |
read | GET /api/v1/integrations/{integrationId}/submitter-logs |
List a WhatsApp integration’s submitter activity log (invitations, OTP verifications, inbound user documents, bot replies), newest first — pagination only (n_per_page/page_number), optionally filtered to one submitter_integration_id. Fails 400 if the target integration is not a WhatsApp integration. Requires EntityIntegrations:Read permission. |
list_integration_submitters |
read | GET /api/v1/integrations/{integrationId}/submitters |
List the submitters attached to a WhatsApp trigger integration — pagination only (n_per_page/page_number), optionally filtered by submitter_channel. Fails 400 if the target integration is not a WhatsApp integration. Requires EntityIntegrations:Read permission. |
resend_integration_submitter_invitation |
write (destructive hint) | POST /api/v1/integrations/{integrationId}/submitters/{submitterId}/resend |
Regenerate the OTP for an INVITED WhatsApp submitter and re-dispatch both the email and WhatsApp invitation template — status stays INVITED. email is required in the body since it isn’t persisted on the submitter row. Fails 409 if the submitter isn’t currently INVITED, 502 on an email/WhatsApp provider failure (safe to retry — the submitter row is unchanged). Requires EntityIntegrations:Write permission. |
Entity accounting account #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_entity_accounting_account |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/accounts |
Create a single accounting account for an entity — code, name, and type are required; compatibility flags control which document line items (AP bill, AR invoice, direct expense, bank statement) can use it. Requires EntityAccounting:Write permission. |
delete_entity_accounting_account |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/accounts/{id} |
Archive (soft-delete) a single accounting account by id — recoverable via update_entity_accounting_account with unarchive true. Returns no content on success (204). Requires EntityAccounting:Write permission. |
delete_entity_accounting_accounts |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/accounts |
Delete every accounting account owned by an entity in one call. Returns no content on success (204). Requires EntityAccounting:Write permission. |
list_entity_accounting_accounts |
read | GET /api/v1/entities/{entityId}/accounting/accounts |
List every accounting account owned by an entity — no pagination in bonsapi; page_number/n_per_page here slice the full result client-side. Requires EntityAccounting:Read permission. |
replace_entity_accounting_accounts |
write (destructive hint) | PUT /api/v1/entities/{entityId}/accounting/accounts/collection |
Replace the entity’s entire accounting account list in one call — the existing list is overwritten outright, not merged. Returns no content on success (204). Requires EntityAccounting:Write permission. |
update_entity_accounting_account |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/accounts/{id} |
Replace a single accounting account by id — code, name, and type are required (full replace, not a partial patch). Set unarchive true to restore an account previously archived via delete_entity_accounting_account; works whether the account is currently active or archived. Returns 404 if the account does not exist. Requires EntityAccounting:Write permission. |
Entity accounting currency #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_entity_accounting_currencies |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/currencies |
Add one or more currencies (ISO 4217 code, e.g. USD, JPY) to an entity in a single batch, each with an optional tax_decimal_places (0-5). Returns no content on success (204). Requires EntityAccounting:Write permission. |
delete_entity_accounting_currency |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/currencies/{currencyId} |
Archive a single accounting currency on an entity by its currency id. Returns no content on success (204). Requires EntityAccounting:Write permission. |
list_entity_accounting_currencies |
read | GET /api/v1/entities/{entityId}/accounting/currencies |
List every accounting currency owned by an entity, each with its tax_decimal_places — no pagination in bonsapi; page_number/n_per_page here slice the full result client-side. Requires EntityAccounting:Read permission. |
replace_entity_accounting_currencies |
write (destructive hint) | PUT /api/v1/entities/{entityId}/accounting/currencies/collection |
Replace the entity’s entire accounting currency list in one call — the existing list is overwritten outright, not merged. Returns no content on success (204). Requires EntityAccounting:Write permission. |
update_entity_accounting_currency |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/currencies/{currencyId} |
Update the tax_decimal_places (0-5, nullable) for a single accounting currency on an entity. Requires EntityAccounting:Write permission. |
Entity accounting tax rate #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
bulk_update_entity_accounting_tax_rates |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/tax-rates/collection |
Update multiple existing tax rates for an entity in one call, each identified by id (name and rate required per item; unlike replace_entity_accounting_tax_rates this only touches the ids you pass). Returns no content on success (204). Requires EntityAccounting:Write permission. |
create_entity_accounting_tax_rate |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/tax-rates |
Create a single tax rate for an entity — name and rate (decimal, e.g. 0.10 for 10%) are required; type (Purchase/Sales) is optional. Requires EntityAccounting:Write permission. |
delete_entity_accounting_tax_rate |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/tax-rates/{id} |
Archive (soft-delete) a single tax rate by id — recoverable via update_entity_accounting_tax_rate with unarchive true. Returns no content on success (204). Requires EntityAccounting:Write permission. |
delete_entity_accounting_tax_rates |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/tax-rates |
Delete every tax rate owned by an entity in one call. Returns no content on success (204). Requires EntityAccounting:Write permission. |
list_entity_accounting_tax_rates |
read | GET /api/v1/entities/{entityId}/accounting/tax-rates |
List every tax rate owned by an entity — no pagination in bonsapi; page_number/n_per_page here slice the full result client-side. Requires EntityAccounting:Read permission. |
replace_entity_accounting_tax_rates |
write (destructive hint) | PUT /api/v1/entities/{entityId}/accounting/tax-rates/collection |
Replace the entity’s entire tax-rate list in one call — the existing list is overwritten outright, not merged. Returns no content on success (204). Requires EntityAccounting:Write permission. |
update_entity_accounting_tax_rate |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/tax-rates/{id} |
Replace a single tax rate by id — name and rate are required (full replace, not a partial patch). Set unarchive true to restore a tax rate previously archived via delete_entity_accounting_tax_rate; works whether the tax rate is currently active or archived. Returns 404 if the tax rate does not exist. Requires EntityAccounting:Write permission. |
Entity accounting contact #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_entity_accounting_contact |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/contacts |
Create a single accounting contact for an entity — code and name are required; is_supplier/is_customer/default_currency/tax_identification_number are optional. Requires EntityAccounting:Write permission. |
delete_entity_accounting_contact |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/contacts/{id} |
Archive (soft-delete) a single accounting contact by id — recoverable via update_entity_accounting_contact with unarchive true. Returns no content on success (204). Requires EntityAccounting:Write permission. |
delete_entity_accounting_contacts |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/contacts |
Delete every accounting contact owned by an entity in one call. Returns no content on success (204). Requires EntityAccounting:Write permission. |
list_entity_accounting_contacts |
read | GET /api/v1/entities/{entityId}/accounting/contacts |
List every accounting contact owned by an entity — no pagination in bonsapi; page_number/n_per_page here slice the full result client-side. Requires EntityAccounting:Read permission. |
replace_entity_accounting_contacts |
write (destructive hint) | PUT /api/v1/entities/{entityId}/accounting/contacts/collection |
Replace the entity’s entire accounting contact list in one call — the existing list is overwritten outright, not merged. Returns no content on success (204). Requires EntityAccounting:Write permission. |
update_entity_accounting_contact |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/contacts/{id} |
Replace a single accounting contact by id — code and name are required (full replace, not a partial patch). Set unarchive true to restore a contact previously archived via delete_entity_accounting_contact; works whether the contact is currently active or archived. Returns 404 if the contact does not exist. Requires EntityAccounting:Write permission. |
Entity accounting tag #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_entity_accounting_tag |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/tags |
Create a single accounting tag (tracking category/option) for an entity — name and is_selectable are required; parent_id (null for a root category) and code are optional. Requires EntityAccounting:Write permission. |
update_entity_accounting_tag |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/tags/{id} |
Replace a single accounting tag by id — name and is_selectable are required (full replace, not a partial patch); parent_id null moves it to root. To archive/reactivate a tag instead, use update_entity_accounting_tag_status. Requires EntityAccounting:Write permission. |
update_entity_accounting_tag_status |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/tags/{id}/status |
Archive or reactivate a single accounting tag by id — set active false to archive it, true to reactivate. Requires EntityAccounting:Write permission. |
Entity accounting item #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_entity_accounting_item |
write (destructive hint) | POST /api/v1/entities/{entityId}/accounting/items |
Create a single accounting item for an entity — type is required; code, name, sales_price, description, default_account_id, and default_tax_rate_id are optional. Requires EntityAccounting:Write permission. |
delete_entity_accounting_item |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/items/{id} |
Archive (soft-delete) a single accounting item by id — recoverable via update_entity_accounting_item with unarchive true. Returns no content on success (204). Requires EntityAccounting:Write permission. |
delete_entity_accounting_items |
write (destructive hint) | DELETE /api/v1/entities/{entityId}/accounting/items |
Delete every accounting item owned by an entity in one call. Returns no content on success (204). Requires EntityAccounting:Write permission. |
list_entity_accounting_items |
read | GET /api/v1/entities/{entityId}/accounting/items |
List every accounting item (product/service) owned by an entity — no pagination in bonsapi; page_number/n_per_page here slice the full result client-side. Requires EntityAccounting:Read permission. |
replace_entity_accounting_items |
write (destructive hint) | PUT /api/v1/entities/{entityId}/accounting/items/collection |
Replace the entity’s entire accounting item list in one call — the existing list is overwritten outright, not merged. Returns no content on success (204). Requires EntityAccounting:Write permission. |
update_entity_accounting_item |
write (destructive hint) | PATCH /api/v1/entities/{entityId}/accounting/items/{id} |
Replace a single accounting item by id — code, name, and type are required (full replace, not a partial patch). Set unarchive true to restore an item previously archived via delete_entity_accounting_item; works whether the item is currently active or archived. Returns 404 if the item does not exist. Requires EntityAccounting:Write permission. |
Reference data #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
accounting_tag_usage |
read | GET /api/v1/entities/{entityId}/accounting/tags/{id}/usage |
Get invoice and direct-expense usage counts for a single accounting tag on an entity — read the description in the accounting_tags tool for context. Requires EntityAccounting:Read permission. |
accounting_tags |
read | GET /api/v1/entities/{entityId}/accounting/tags |
List every accounting tag (tracking category/option, e.g. Xero’s tracking categories) configured for an entity and extraction type — the fields that accounting-sync uses when publishing to Xero/QuickBooks. Requires EntityAccounting:Read permission. |
apply_knowledge_templates |
write (destructive hint) | POST /api/v1/knowledge/templates |
Apply pre-built country-specific knowledge templates to an entity. Templates provide field-mapping guidance for the country’s invoicing, direct-expense, and bank-statement extractions. Returns the merged knowledge set after applying templates (some cards may be duplicates or updates to existing ones). Requires EntityKnowledge:Write permission. |
get_accounting_target_config |
read | GET /api/v1/accounting/targets/{key}/config |
Fetch extraction config defaults and configurable constraints for a single accounting target (e.g. CSV export field options and limits for that target software). key must be one of the values returned by get_accounting_targets. Returns 404 if the key is not a supported target. |
get_accounting_targets |
read | GET /api/v1/accounting/targets |
List every supported accounting-target software key (e.g. Xero, QuickBooks) as an enum value — used to populate target_accounting_software on update_entity_settings and to know which keys get_accounting_target_config accepts. |
get_countries |
read | GET /api/v1/countries |
List every country bonsapi recognizes (ISO 3166-1 alpha-2 code only, e.g. US, JP). Used by create_knowledge_card and other endpoints that validate country-specific fields. |
get_currencies |
read | GET /api/v1/currencies |
List every currency bonsapi recognizes (ISO 4217 code and its tax rounding decimal places, e.g. USD: 2, JPY: 0). Used when creating knowledge cards and other currency-specific fields. |
get_priority_fields |
read | GET /api/v1/priority-fields |
List the priority fields configured for an entity and extraction type — the fields that appear at the top of the UI and are validated/extracted first. Priority fields are set via entity knowledge (knowledge cards). Requires EntityKnowledge:Read permission. |
replace_priority_fields |
write (destructive hint) | PUT /api/v1/priority-fields |
Replace the full set of priority fields for an entity and extraction type in one call — the existing list is overwritten outright, not merged. Requires extraction_type and fields (max 3 field names) in the body. Requires EntityKnowledge:Write permission. |
Organization #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
get_organization_analytics |
read | GET /api/v1/organization/analytics |
Fetch the caller’s organization’s usage analytics: usage_metrics (daily per-entity extraction counts, split tofu-vs-external, for invoices/direct-expenses/bank-statements), review_analytics (per-entity counts of extractions/documents currently in review), and entity_usage_summary (per-entity integration/extraction/verification totals). No per-user or unique-user breakdown is included anywhere in the response. Used by billing and usage-tracking dashboards. |
get_organization_by_external_id |
read | GET /api/v1/organizations/{externalId} |
Fetch organization details (id, name, slug, created_at/updated_at) by its external ID (e.g. Stripe subscription id, Xero tenant id). Used by integrations to look up the organization in Bonsai from external systems. |
get_organization_members |
read | GET /api/v1/organization/members |
List all members of the organization with their roles. Requires Organization:Read permission. |
get_organization_roles |
read | GET /api/v1/organization/roles |
List every entity role available in the caller’s organization (id, name, created_at). Roles are custom per-organization; each role has a set of permissions (read/write/admin/etc.). Used by add_entity_member and update_entity_member to populate role dropdowns. |
get_organization_settings |
read | GET /api/v1/organization/settings |
Fetch the caller’s organization’s settings: whether integration-trigger emails are disabled, whether the org is in read-only/archival mode, and organization-level field configuration defaults. Requires Organization:Admin role. |
get_public_organization_settings |
read | GET /api/v1/organization/public-settings |
Fetch the same email-domain-whitelist and knowledge-sharing settings as get_organization_settings, but exposed to any authenticated member — no Organization:Admin role check, JWT authentication alone is sufficient. Useful when a lower-privileged caller needs to read these settings (e.g. to render a banner) without being able to fetch or change the admin-only settings resource. |
update_organization_settings |
write (destructive hint) | PATCH /api/v1/organization/settings |
Update the caller’s organization’s settings: whether integration-trigger emails require an email-domain whitelist, and whether the organization has opted in to share knowledge data. Both fields are optional and independent — pass only what you want to change; an omitted field keeps its current value. Returns the full updated settings object (same shape as get_organization_settings), including the new updated_at timestamp. Requires Organization:Admin role. |
User account #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
get_billings |
read | GET /api/v1/billings |
Fetch the caller’s organization’s current billing plan, AI extraction usage/limits (monthly/annual), and usage so far this billing period — invoice/direct-expense/bank-statement counts and invoice verification count. |
get_my_prompt_usage |
read | GET /api/v1/users/me/prompt-usage |
Fetch the caller’s own all-time prompt usage: self_prompt_count (number of unique invoices/direct expenses/bank statements the caller has manually verified), and organization-wide context (org_prompt_limit, org_prompt_usage_count — the aggregated counts). |
get_my_verification_count |
read | GET /api/v1/users/me/verification-count |
Fetch the caller’s own invoice verification counts for the last 90 days: total_verified (count of invoices the caller verified), and total_in_organization (count of invoices verified by anyone in the organization). Used by the verify buttons to show progress towards the monthly limit. |
list_coupons |
read | GET /api/v1/billings/coupons |
List the coupons in Stripe’s product catalog that sales can offer a prospect — not a customer’s already-applied discount, and never the welcome or referral coupons tofu applies itself. Each entry includes id (the code to quote/apply), name, either amount_off + currency or percent_off, duration (forever/once/repeating, with duration_in_months for repeating), max_redemptions and times_redeemed so far, redeem_by (Unix seconds; absent means no expiry), and valid — Stripe’s own up-to-date ‘can this still be redeemed’ flag. Always check valid before offering a coupon: an expired or maxed-out one is still returned so the record is auditable, but should not be quoted to a prospect. |
list_pricing_plans |
read | GET /api/v1/billings/pricing-plans |
List active Stripe pricing plans (basic catalog data, no per-org sales overrides). Pass country (ISO 3166-1 alpha-2, e.g. ‘GB’, ‘JP’) to resolve pricing to that market the same way the webapp does from the caller’s IP — ask which country the caller is in if you don’t already know; omitted or unrecognized defaults to USD. Each price’s amount is localized to that market’s currency when Stripe has one, else USD, else its own base currency. Each plan includes id, name, description, tagline, and its prices (amount, currency, billing interval, any AI-extraction allowance with its limit interval, any entity cap via max_entities — absent means unlimited for either — and an optional per-price tagline distinct from the plan-level one). Normally only the prices shown on the billing page are returned (the price’s own is_in_app metadata set to true). When onboarding v2 is enabled, a caller who can manage billing in an organization that is still onboarding gets the onboarding catalog instead (is_self_serve set to true): it can include prices the billing page doesn’t show, which can only be bought during onboarding. Either way, every other price is withheld and a plan with none left is omitted, so anything you get back here is safe to quote to this caller. Each returned price still carries its own billing interval (monthly or yearly) and its own allowance reset interval, which are independent: quote both from the price itself rather than assuming. |
Knowledge #
| Tool | Effect | Endpoint | Description |
|---|---|---|---|
create_knowledge |
write (destructive hint) | POST /api/v1/knowledge |
Create a new knowledge item for an entity. Requires entity_id, extraction_type, and content. Optional fields: title, knowledge_type (defaults to EXTRACTION), target_fields. Requires EntityKnowledge:Create permission. |
delete_knowledge |
write (destructive hint) | DELETE /api/v1/knowledge/{entityKnowledgeId} |
Delete a knowledge item permanently. Requires EntityKnowledge:Update permission. Returns no content on success (204). |
get_contact_learnings |
read | GET /api/v1/contact-knowledge/learnings |
Get the most recent contact-knowledge learning for every contact on an entity, aggregated by contact name. Contact learning is tofie’s in-flight learning for individual contacts (e.g. preferred email, phone number format) that overrides or augments entity-level knowledge. Requires EntityKnowledge:Read permission. |
list_knowledge |
read | GET /api/v1/knowledge |
List knowledge items for an entity, optionally filtered by extraction_type, target_external_contact_id, version (entity_knowledge_version), and/or knowledge_type (EXTRACTION or PAGE_CLASSIFICATION, defaults to EXTRACTION). Supports client-side pagination (limit/offset) on top of the full filtered result set. Requires EntityKnowledge:Read permission. |
list_knowledge_conflicts |
read | GET /api/v1/knowledge/conflicts |
List pending entity-knowledge conflicts for an entity and extraction type — cases where an existing knowledge card is about to be overwritten or deleted. Caller can resolve them with resolve_knowledge_conflict (keep new or discard new). Requires EntityKnowledge:Read permission. |
list_knowledge_history |
read | GET /api/v1/knowledge/history |
List the version history for a knowledge card, or for an entire entity. If entity_knowledge_id is provided, returns history for that card only; if omitted, returns all history for the entity filtered by version (version defaults to the entity’s current entity_knowledge_version when not given). Requires EntityKnowledge:Read permission. |
list_knowledge_templates |
read | GET /api/v1/knowledge/templates |
List pre-built knowledge templates available to apply to an entity via apply_knowledge_templates — distinct from that tool, this one only lists candidates and applies nothing. Optionally filter by country (comma-separated ISO 3166-1 alpha-2 codes, e.g. “SG,MY” — templates with an empty countries list are global and always included regardless of this filter) and scope (comma-separated; COUNTRY is the only scope today). Requires EntityKnowledge:Read permission. |
resolve_knowledge_conflict |
write (destructive hint) | PATCH /api/v1/knowledge/conflicts/{conflictId} |
Resolve a pending knowledge card conflict by either keeping or discarding the conflicting new version. Send {resolution: “keep”} to accept the conflicting version or {resolution: “discard”} to reject it and keep the existing one. Requires EntityKnowledge:Update permission. |
revert_knowledge |
write (destructive hint) | POST /api/v1/knowledge/{entityKnowledgeId}/revert |
Revert a knowledge item to a specific previous version using its history ID. The tool returns all versions of the knowledge item after reverting so the caller can confirm or revert again. Requires EntityKnowledge:Update permission. |
update_knowledge_card |
write (destructive hint) | PATCH /api/v1/knowledge/{entityKnowledgeId} |
Update a single knowledge card’s contents, title, target_fields, or preferred language via a genuine single-item PATCH. Pass only the fields you want to change; omitted fields keep their old values (at least one of contents/title/target_fields is required — preferred_language alone does not count as an update). Infer preferred_language from the language the user is writing to you in (as an English language name, e.g. “Japanese”), not just an explicit language request, and pass it explicitly whenever you can — it is never inferred from a previously-stored value (bonsapi does not persist or return preferred_language). If omitted, it resolves to the caller’s own UI locale, then is left unset. The resolved value is echoed back in the response. Requires EntityKnowledge:Update permission. |
upsert_knowledge_cards |
write (destructive hint) | PUT /api/v1/knowledge |
Create or update multiple knowledge cards in a single batch operation — an upsert matched by id: items with an existing card id are updated, items without one are created new. Existing cards not referenced in this call are left untouched; this does not replace or wipe the entity’s knowledge base. For an update item, contents/title/target_fields are each independently patchable: omit a field to leave that card’s existing value unchanged, or pass an empty string/array to explicitly clear title/target_fields. A new item requires both contents and extraction_type (or extraction_types). Infer each item’s preferred_language from the language the user is writing to you in (as an English language name, e.g. “Japanese”), not just an explicit language request, and pass it explicitly whenever you can. If an item omits preferred_language, it resolves to the caller’s own UI locale, then is left unset. The resolved value is echoed back in the response. Requires EntityKnowledge:Write permission. Returns the created/updated items from this batch. |