# Biloh > Biloh is the operating system for service businesses — quotes, dispatch, > contractor management, jobs, invoicing — usable from a phone, with > Model Context Protocol (MCP) integration bundled at every tier. ## What this file is This is a llms.txt manifest, per https://llmstxt.org/, intended to make Biloh discoverable and usable by AI agents and crawlers. ## How to integrate via MCP Biloh exposes a Model Context Protocol server. AI agents (Claude, GPT, Grok, Perplexity, or any MCP-compatible client) can drive a Biloh tenant's operations end-to-end through this surface. - MCP endpoint: https://app.biloh.com.au/api/mcp - Spec: https://modelcontextprotocol.io - Tier inclusion: every Biloh tier (Basic, Pro, Enterprise, Custom) ## Documentation - Marketing site: https://biloh.com.au - Features overview: https://biloh.com.au/features - Pricing and tiers: https://biloh.com.au/pricing - MCP integration: https://biloh.com.au/mcp - About: https://biloh.com.au/about - Contact: hello@biloh.com.au ## Documentation pages The published docs at https://biloh.com.au/docs. The full text of every doc, concatenated for agents, is at https://biloh.com.au/llms-full.txt. - Scheduling jobs by the day, not the minute: https://biloh.com.au/docs/concepts/scheduling-jobs-by-the-day - How Biloh handles money: the two Stripe tills: https://biloh.com.au/docs/concepts/two-stripe-tills - When completing a job bills the client: https://biloh.com.au/docs/concepts/when-completing-a-job-bills-the-client - Show the price you'll charge: one source of truth: https://biloh.com.au/docs/engineering-notes/displayed-equals-charged - Drag is a desktop idiom; the phone wants a tap: https://biloh.com.au/docs/engineering-notes/drag-is-a-desktop-idiom - The gap between a green build and a live deploy: https://biloh.com.au/docs/engineering-notes/green-build-vs-live-deploy - Lessons from shipping agent-facing MCP tools: https://biloh.com.au/docs/engineering-notes/lessons-shipping-agent-tools - When the money arrives but can't be recorded: https://biloh.com.au/docs/engineering-notes/money-received-but-unrecorded - Making a multi-connector MCP setup safe to act on: https://biloh.com.au/docs/engineering-notes/multi-tenant-mcp-safety - One write path, many callers: https://biloh.com.au/docs/engineering-notes/one-write-path-many-callers - Tool discoverability for agents: https://biloh.com.au/docs/engineering-notes/tool-discoverability-for-agents - Trust the signed account, not the webhook's metadata: https://biloh.com.au/docs/engineering-notes/trusting-signed-webhook-fields - Verifying the tenant that isn't your default: https://biloh.com.au/docs/engineering-notes/verifying-the-tenant-that-isnt-your-default - A handler nothing subscribes to does nothing: https://biloh.com.au/docs/engineering-notes/wiring-an-event-to-its-handler - What is Biloh?: https://biloh.com.au/docs/getting-started/what-is-biloh - How to send a proposal: https://biloh.com.au/docs/how-to/send-a-proposal - Connecting Biloh over MCP: https://biloh.com.au/docs/reference/mcp-overview ## Tools (auto-generated catalogue) The operator-persona toolset is listed below. Architect-only and platform-internal tools are not included. Names are stable; semantics may evolve. - list_clients: Returns clients for the authenticated user's tenant. Supports filtering by status, free-text search via `query` (case-insensitive substring match across legal_name, trading_name, and billing_email), a - get_client: Returns a single client by ID for the authenticated user's tenant. Returns the full client row including legal_name, trading_name, ABN, billing_email, status, and metadata. - get_client_footprint: Returns a one-shot, read-only dependency rollup for a client (or contractor/site): counts + sample ids of every attached site, contract_service_line (active vs inactive), job (by status), proposal (by - get_client_portal_link: Returns the client's persistent portal URL (the /portal/client/{token} link) and its underlying portal token. Mirror of get_contractor_portal_link (WP-CLIENT-PORTAL-LINK-RECOVERY, bugs e843138b + 2178 - resend_client_portal_link: Email a client's persistent portal link (the /portal/client/{token} URL) to their stored billing email. The delivery half of lost-email portal recovery — the MCP-native mirror of the operator UI 'Rese - list_sites: Returns sites for the authenticated user's tenant. Optionally filtered by client_id. Excludes soft-deleted rows. - get_site: Returns a single site by ID for the authenticated user's tenant. Returns address, geo coords, notes (access / hazards / legal), associated client_id, and metadata. - list_site_contacts: Returns contacts for a site (or every contact across the tenant if site_id is omitted). Canonical table is `site_contacts` — the legacy `client_contacts` table is deprecated. Each contact has name, ro - lookup_abn: Looks up an Australian business via the Australian Business Register (ABR). Supports two modes: (1) ABN lookup — provide `abn` to get verified details for a known ABN; (2) Name search — provide `name` - create_client: Creates a new client record for the tenant. A client is a business entity that contracts the tenant for services. When billing_email is provided, a default site and billing contact are auto-created so - update_client: Updates an existing client's business details, billing info, payment terms, or status. Only provided fields are changed. - create_site: Creates a new site (service location) linked to a client. Sites represent physical locations where services are delivered. Use `access_notes` for contractor access instructions and `legal_notes` for c - create_site_contact: Creates a contact person at a site. Contacts receive notifications based on their `contact_role` (owner, primary, billing, backup, emergency, technical). Role defaults auto-set notification flags; exp - update_site_contact: Updates a site contact's details or notification preferences. Only provided fields are changed. - update_site: Updates an existing site's name, address, or notes. Only provided fields change; omitted fields are preserved. - list_contractors: Returns contractors for the authenticated user's tenant with pagination. Excludes soft-deleted rows. Excludes test rows (is_test=true) by default — pass include_test:true to include them. - get_contractor: Returns a single contractor by ID for the authenticated user's tenant. Returns business details, ABN, primary contact, sma_status, availability, capabilities, and denormalised compliance snapshot. - get_contractor_portal_link: Returns the contractor's persistent portal URL (the /portal/contractor/{token} link) and its underlying portal token. Mirrors the client portal_token surface. Idempotent: reuses the existing token if - list_contractor_agreements: Returns agreements (SMAs etc.) for a contractor with their current status (draft / sent / accepted / declined / expired). - list_contractor_quotes: Returns quotes a contractor has submitted for site/service combinations. Quotes are contractor-side reference data used when negotiating contract_service_line rates. - list_contractor_compliance_documents: Returns compliance documents (insurance certificates, ABN verifications, workers comp, etc.) for a contractor with their verification status and expiry dates. - create_contractor: Creates a new contractor (sub-contractor) for the tenant. Contractors are businesses that perform services on behalf of the tenant. Captures business_name, ABN, contact details, capabilities, and init - update_contractor: Updates a contractor's business details, insurance, banking, availability, or capabilities. Most fields are operator-accessible; banking fields (`bank_bsb`, `bank_account_number`, `bank_account_name`) - contractor_visible_notes: Read or write the CONTRACTOR-FACING free-text note on a payable or job. This note is DISTINCT from the operator-only `notes` column — the internal `notes` is never shown to a contractor; only this not - create_contractor_contact: Creates a contact person for a contractor. Each contact is a person with name, role, phone, email, and notification preferences. - add_contractor_service_capability: Declares that a contractor is configured/qualified to deliver a given service by adding a row to the `contractor_services` capability map. This is the row the `assign_job` compliance gate checks (lib/ - list_contractor_contacts: Returns contacts for a contractor. Each contact is a person with name, role, phone, email, and notification preferences. - update_contractor_contact: Updates a contractor contact's details or notification preferences. Only provided fields are changed. - create_contractor_agreement: Creates a contractor agreement (SMA — Subcontractor Master Agreement) record in `draft` status. Agreements track the legal relationship between tenant and contractor. A draft must exist before propose - create_contractor_quote: Creates a contractor quote — a price a contractor has offered for a specific site/service combination. Quotes are reference data used when negotiating contract_service_line rates. - create_contractor_compliance_document: Creates a compliance document record (insurance certificate, ABN verification, workers comp, etc.) for a contractor. Documents track the contractor's regulatory compliance status. Newly created docs s - verify_contractor_abn: Verifies a contractor's stored ABN against the Australian Business Register (ABR) and sets abn_verified=true when the ABN is ACTIVE. A collected ABN is already a satisfied prerequisite; this is the au - list_compliance_documents_pending_review: Lists all compliance documents with status 'pending_review' for the tenant — the agent review queue. Results are oldest-first so the automation works FIFO. - record_compliance_review: Records a reviewing agent's verdict on a compliance document. The platform NEVER calls an LLM — whoever drives the MCP client brings their own model. This tool records the extracted fields and verdict - create_compliance_upload_link: Generates a short-lived, single-use upload link for a contractor's compliance document (insurance certificate, photo, scan). Give this link to the user — they tap it on their phone, pick a photo/scan/ - list_services: Returns the service catalog for the authenticated user's tenant. Services are CLIENT-AGNOSTIC and CONTRACTOR-AGNOSTIC — they describe what work is offered, not who it's for. Excludes soft-deleted rows - list_frequencies: Returns the frequency catalog (scheduling patterns: weekly, fortnightly, 4-weekly, etc.) for the authenticated user's tenant. Frequencies are referenced by contract_service_lines to determine job recu - list_contract_service_lines: Returns the rate schedule lines (per site/service/contractor) for the tenant. Optionally filtered by site_id, service_id, contractor_id, or client_id (resolved via the client's sites). Each row carrie - get_contract_service_line: Returns full details for a single contract service line, including recurrence data (rrule_string, human_description — the authoritative cadence label, preferred over frequency_name which can lag a day - create_service: Creates a generic, reusable service in the tenant's catalog. Services are CLIENT-AGNOSTIC and CONTRACTOR-AGNOSTIC — they describe what work is offered, not who it's for or who delivers it. - update_service: Updates fields on a generic catalog service. Only provided fields are changed. The same content rules as create_service apply: services are CLIENT-AGNOSTIC and CONTRACTOR-AGNOSTIC. - archive_service: Soft-deletes a service from the catalog (sets `deleted_at`). The service row remains in the database for audit history and FK references from existing contract_service_lines / jobs, but is excluded fr - create_frequency: Creates a new frequency in the tenant's catalog. Frequencies define scheduling patterns (e.g., weekly, fortnightly, 4-weekly) used by contract_service_lines to determine job recurrence. - update_frequency: Updates an existing frequency's fields. Only provided fields are changed. - archive_frequency: Soft-deletes a frequency from the catalog (sets `deleted_at`). The frequency row remains in the database for audit history and FK references from existing CSLs, but is excluded from active queries. - create_contract_service_line: Creates a contract service line — THE place for client-specific pricing. Links a site to a service with a frequency, client_rate_cents, and optional contractor_rate_cents. This is where per-client, pe - update_contract_service_line: Updates a contract service line's rates, active status, contractor assignment, active months, service (in-place swap), or recurrence inputs (day_of_week, week_of_month, anchor_date). This is where rat - onboard_client_for_service: One-step composite to set up a client's service at a site with correct pricing. Creates a contract_service_line and optionally appends special conditions to site.legal_notes. ENFORCES correct data pla - list_jobs: Returns jobs (work orders, scheduled visits) for the tenant. Optionally filtered by status, site_id, contractor_id, or date range. Excludes test rows (is_test=true) by default — pass include_test:true - get_job: Returns a single job by ID with full details including status, site, contractor, schedule, notes, completion photos, and completion data. - create_job: Creates a new job (work order) for a site/service on a scheduled date. Jobs represent individual instances of work to be performed. Should reference a contract_service_line where one exists. The job s - update_job: Updates a job's status, schedule, contractor assignment, or notes. Valid statuses: scheduled, dispatched, completed, approved, invoiced, paid, on_hold, cancelled, missed, partial. General-purpose; spe - record_completion: Records contractor completion of a job: sets `status='completed'`, `completion_submitted_at`, `completion_photos[]`, `completion_notes`. Validates min photos + notes per the tenant's contractor-portal - record_field_triage: Records a field-triage event on a dispatched job — the operator/MCP twin of the contractor portal 'Can't complete' flow. Sets the job's hold_reason from reason_code (+ optional note), auto-reschedules - list_work_orders: Returns work orders for the tenant. Optionally filtered by status, job_id, contractor_id, scope, or contract_service_line_id. Status values: sent, accepted, declined, rejected_after_acceptance, expire - get_work_order: Returns a single work order by ID with full details including signing token, acceptance record, and signed PDF URL. WP-WO-01 scope model: the response includes `scope` (single_job / job_set / ongoing_ - approve_send_work_order: Approves a staged work-order send and immediately dispatches the email to the contractor with a portal-link CTA. Mints the signing_token, creates the `work_orders` row, sends the branded email, and em - record_work_order_acceptance: Records an out-of-band work-order acceptance (e.g. contractor accepted verbally or via email, and the operator is back-filling the system). Creates an immutable `work_order_acceptances` row and flips - cancel_work_order: Cancels an in-flight work order and invalidates its acceptance link. Soft transition: the row is KEPT (status='cancelled'), the signing_token is expired so the portal accept link stops working, and `w - list_invoices: Returns invoices for the tenant. Filter by client_id, status, since (ISO date). Returns totals as integer cents plus lock_version, is_catch_up_invoice, and client_po_number on every row. By default hi - get_invoice: Returns a single invoice by ID with its lines, totals (integer cents), lock_version, status, ATO fields (supplier/buyer), client_po_number, dates, is_catch_up_invoice flag, and live payment position: - get_payment: Returns a payment by ID with its allocations against invoices (m:n via payment_allocations). Amounts in integer cents. `payment_date` is the real-world bank/cash receipt date (per Finance Engine Princ - list_payments: Returns payments for the tenant, filtered by invoice_id (via allocations), client_id, since (ISO date). Amounts in integer cents. By default hides `is_test=true` rows. - import_bank_csv: Ingest a CommBank NetBank CSV export into the bank-reconciliation feed (bank_transactions). The CSV is header-less with 4 columns: date (DD/MM/YYYY), signed amount (credit +, debit -), description, ru - list_bank_transactions: Returns ingested bank transactions for the tenant, filtered by match_state (unmatched | suggested | matched | ignored), direction (credit | debit), and a value_date window (since/until ISO dates). Amo - ignore_bank_transaction: Mark a bank transaction as a non-sale (bank interest, an internal transfer, a random deposit or refund) so it leaves the reconciliation worklist. A reason is REQUIRED for the audit trail. This is the - get_reconciliation_suggestions: Ranks each unmatched incoming bank credit against the tenant's outstanding invoices, returning suggested matches with a deterministic confidence score, the reasons (exact_amount, invoice_ref_in_descri - get_sales_gst_report: The accountant's month-end artifact: the CASH-BASIS Sales & GST report for a period. Returns one row per payment RECEIVED (invoice number, issue date, paid date, client, ex-GST cents, GST cents, total - get_month_end_status: Returns the month-end CLOSE state for a period plus a LIVE summary. `state` is 'open' (no close exists yet), 'closed' (locked — figures frozen), or 'reopened' (was closed, now editable again). `live` - run_month_end_close: Closes (locks) a month-end period. Computes the cash-basis figures for the period and SNAPSHOTS them (received / ex-GST / GST / receipt_count / outstanding_ar) into the period_closes record, marking t - reopen_period: Reopens a previously-closed month-end period so its figures can be corrected, then re-closed. Sets the period_closes record to 'reopened' and records a REQUIRED reason plus who/when — the reason is th - attest_payment: Record how a payment physically landed: the BANKED portion (will appear on this account's bank feed) and the UNBANKED portion (cash retained, or deposited to another account). The invariant is banked_ - get_payment_attestation: Return the provenance attestation for a payment — the banked vs unbanked split (banked_cents, unbanked_cents, unbanked_method, note) recorded by attest_payment — or null if the payment has not been at - unmatch_reconciliation: Undo a reconciliation: reverse a deposit that was matched to an invoice. It VOIDS the payment the match created (which unwinds the payment's allocation and recomputes the invoice off 'paid'), then fre - get_payable: Returns a contractor payable by ID with its linked invoice (id+status) for Layer-2 cash-flow visibility. Amount in integer cents. `payable_paid_date` is the real-world payment date (Finance Engine Pri - list_payables: Returns contractor payables for the tenant, filtered by contractor_id / status / since. Amounts in integer cents. Default hides `is_test=true`. - get_credit: Returns a client credit by ID. `source` distinguishes overpayment | prepayment | adjustment | refund_reversal (lock-in B2 — prepayments arrive before any invoice). Amount in integer cents. - list_credits: Returns client credits for the tenant, filtered by client_id, source, since. Amounts in integer cents. Default hides `is_test=true`. - get_refund: Returns a refund by ID with its linked payment summary (lock-in B8.1 linkage). `refund_date` is the real-world execution date; `refund_reason` is required non-empty. Amount in integer cents. Voided re - list_refunds: Returns refunds for the tenant, filtered by payment_id, since (refund_date). Amounts in integer cents. Default hides `is_test=true`. - get_statement: Returns a statement by ID with its items (invoice + payment line refs). `bundle_invoices` flag indicates whether the eventual email attaches per-invoice PDFs. Amounts in integer cents. - list_statements: Returns statements for the tenant, filtered by client_id and since (period_end). Amounts in integer cents. Default hides `is_test=true`. - get_finance_settings: Returns the tenant's finance configuration from two sources: (1) registry-backed settings (category=finance) with current values, defaults, and tier status; (2) tenant-level finance columns (payment t - update_tenant_finance_profile: Updates tenant-level finance columns and/or business profile identity. These fields live directly on the tenants table (not the settings registry). This is the MCP counterpart to the Financial Default - list_invoice_state_changes: Returns chronological state-transition rows from `audit_log` for invoices in this tenant (entity_type='invoice', filtered to state-transition verbs: created, send/sent, paid, partially_paid, overdue, - get_payable_release_status: Returns the Layer 2 cash flow protection gate state for a contractor payable: whether it is releasable and why/why-not, plus the linked client invoice's status, PO, and paid date. - propose_release_payable: Stages a contractor payable release for operator approval. Validates that the Layer 2 gate (linked client invoice must be paid) is passable BEFORE staging — if blocked, returns the specific gate code - approve_release_payable: Approves a staged contractor payable release and atomically transitions the payable to status='released'. Emits payable.released with idempotency key. Re-validates the Layer 2 gate (invoice still paid - mark_invoice_paid: Marks a client invoice as paid WITHOUT recording an underlying payment row. Manual-override / paper-only reconciliation path. The canonical operator workflow for received money is record_payment (comp - create_invoice: Creates a draft invoice for a client with one or more line items. Auto-generates an invoice_number (next sequential via finance.invoicing.numbering_prefix setting), resolves the client PO via the casc - create_invoice_from_proposal: Composite: creates a DRAFT invoice directly from an ACCEPTED proposal. Resolves the client from the proposal, copies each live proposal line to an invoice line (proposal amounts are EX-GST by schema c - update_invoice: Updates the header fields of a draft invoice (subject_line, notes, client_po_number, due_date). Issued invoices are immutable — attempting to edit a sent/overdue/paid/voided invoice returns code:'immu - void_invoice: Voids an invoice in draft/sent/overdue/disputed status. REJECTS attempts to void a paid invoice — the correction path for paid is the refund flow (FE-05) + a credit note. Requires a non-empty void_rea - add_invoice_line: Adds a line item to a draft invoice. Recomputes header totals (subtotal/gst_amount/total) atomically from non-deleted lines. Increments lock_version. Issued invoices are immutable — non-draft attempts - update_invoice_line: Updates an existing line on a draft invoice. Recomputes line GST + header totals atomically. Issued invoices are immutable. - remove_invoice_line: Soft-removes a line from a draft invoice (sets deleted_at). Recomputes header totals. Issued invoices are immutable. - validate_invoice: Runs the locale-specific tax-invoice validator against a draft or sent invoice and returns the structured result (ok + code + reason + carry-through fields). v1 ships the AU ruleset (lock-in B5 + WP-F - recalculate_invoice_gst: Recomputes per-line and header GST on a draft invoice from current `gst_treatment` flags. Bumps `lock_version`. Emits `invoice.gst_recalculated`. Lines with `gst_treatment='mixed'` PRESERVE their stor - approve_send_invoice: Approves a staged invoice send (leg 3 of 3 in the propose → confirm → approve send chain). Runs the locale-specific ATO validator (per WP-FE-06 + lock-in B5) as a HARD GATE: on validation failure the - propose_resend_invoice: Stages a re-delivery of an already-sent invoice to all finance contacts (or an explicit override). The invoice must be in `sent`, `overdue`, or `partially_paid` status. Returns a pending_operation_id; - propose_record_payment: Stages a client payment recording for operator approval. Validates date discipline, amount, payment method, invoice state, and external-reference idempotency BEFORE staging. If the gate would block, r - approve_record_payment: Approves a staged payment recording and atomically inserts the payment row, allocation, transitions the invoice (to partially_paid or paid), and emits payment.recorded + (conditional) invoice.partiall - void_payment: Soft-deletes a payment and rolls back the linked invoice's status. Required void_reason + void_date for audit-trail discipline. Use for typo recovery (wrong amount, wrong invoice) or bank reversal (de - void_payable: Soft-deletes a non-released contractor payable (status → 'void', deleted_at set). Required void_reason + void_date for audit-trail discipline. The symmetric partner to void_payment for the contractor - propose_record_refund: Stages a client refund recording for operator approval. Refund anchors to a payment (lock-in B8.1) and requires a non-empty refund_reason (B8.2). Validates date discipline, amount, method, payment sta - approve_record_refund: Approves a staged refund recording and atomically inserts the refund row, recomputes the linked invoice's status (paid → partially_paid or sent/overdue depending on effective allocation), handles link - void_refund: Soft-deletes a refund and rolls the linked invoice's status forward. Required void_reason + void_date for audit-trail discipline. Use for typo recovery (wrong amount, wrong refund) or refund returned - create_credit_note: Creates a DRAFT credit note against an existing sent invoice. Credit notes anchor to invoices (not payments — refunds do that), reduce the invoice's effective settled amount on send, and carry the ori - update_credit_note_line: Patches a credit-note line. Only valid while the credit note is in draft. Recomputes the line's GST + the header totals automatically. - approve_send_credit_note: Approves a staged credit-note send. Runs the locale-specific ATO validator (per FE-06 reuse — same rules for credit notes as invoices) as a HARD GATE. On refusal returns a structured failure (ok:false - propose_resend_credit_note: Stages a re-delivery of an already-sent credit note to all receives_invoices contacts (credit notes are invoice-family) or an explicit override. The credit note must be in `sent` status. The email fir - get_credit_note: Returns a credit note by ID with its lines + linked invoice projection (status, total, effective settled). - list_credit_notes: Lists credit notes filtered by client / invoice / status / date range. Defaults to excluding test rows. - void_credit_note: Soft-voids a credit note. If the credit note was previously sent, rolls the originating invoice forward (recomputes effective settled). Emits credit_note.voided + (when sent) invoice.credit_unwound. - create_payable: Manually creates a contractor payable row in 'pending' status. CATCH-UP and OPERATOR-OVERRIDE path — the canonical flow is the job.completed handler which auto-creates payables. The release-side gate - backfill_completed_job: Records an already-performed job when the contractor's bill arrives after the fact. ONE CALL creates the completed job + contractor payable with the attested GST-INCLUSIVE bill amount (84f7204f). Retu - get_client_statement: Returns the aggregated client statement view for a date range: opening balance, in-period invoices/payments/refunds, closing balance, outstanding amount, and per-PO subtotals. Amounts in integer cents - list_statement_send_history: Lists statement send and void events for the tenant, sourced from audit_log. Filter by client_id and since (ISO date). Returns chronological actor + action + statement_id + metadata. - propose_send_statement: Proposes sending a statement to a client for a period. Creates a draft `statements` row capturing opening/closing balances + in-period totals, then stages an `mcp_pending_operations` row. Awaits `conf - propose_resend_statement: Stages a re-delivery of an already-sent statement to all receives_statements contacts (or an explicit override). The statement must be in `sent` status. The email fires on `confirm_pending_operation` - void_statement: Soft-marks a statement voided. Operator-attested error recovery (sent the wrong period, wrong client, etc.). Required `void_reason` (non-empty) + `void_date` (ISO YYYY-MM-DD; no default, Principle 3). - get_client_audit_timeline: Returns the chronological financial event timeline for one client over a period. Reads `domain_events` filtered to invoice/payment/refund/statement/payable/proposal/client entities owned by the client - get_invoice_full_history: Returns the complete story of a single invoice: header (with PO + lock_version + status + email_send_status) + state transitions from audit_log + line items + every allocated payment + every refund ag - get_period_reconciliation_view: Returns the two-sided (AR + AP) basis-aware reconciliation view for a period. AR side: invoices broken by lifecycle state (sent/overdue/paid). AP side: payables broken by lifecycle state (pending/rele - find_orphaned_or_unusual_events: Returns the operator-alert anomaly stream — six signal types surfaced by the temporal query layer: - get_xero_connection_status: Returns the Xero connector state for the caller's tenant: whether the integration is enabled (tenant setting), whether an active OAuth connection exists, and the most recent error if any. - get_xero_authorize_url: Returns a one-shot Xero OAuth authorize URL for the caller's tenant. The agent surfaces the URL to the operator as a clickable link; only a browser can complete the OAuth handshake. - list_xero_mirror_log: Returns Xero mirror attempts (synced, failed, skipped) for the caller's tenant, ordered newest-first. - get_xero_mirror_for_entity: Returns the chronological Xero mirror history for a single invoice or payable, plus the current synced Xero entity ID if one exists. - manual_resync_invoice_to_xero: Manually mirrors a biloh invoice to Xero as a draft. Recovery path for invoices that failed to mirror automatically (status='failed' in xero_mirror_log). Idempotent — by default returns 'already_synce - manual_resync_payable_to_xero: Manually mirrors a biloh contractor payable to Xero as a Bill draft. Recovery path for payables that failed to mirror automatically. - disconnect_xero: Disconnects the tenant's Xero integration. Idempotent — calling on an already-disconnected tenant returns already_disconnected:true. Best-effort Xero-side revoke; local connection row is always flippe - get_stripe_connection_status: Returns the Stripe Connect Express state for the caller's tenant: whether the integration is enabled (tenant setting), whether an active connection exists, and the capability flags from Stripe (charge - list_stripe_webhook_events: Lists Stripe webhook events for THIS tenant's CONNECTED (Till-2 / Connect) Stripe account only, sorted newest-first — e.g. payment_intent.succeeded / checkout.session.completed for the tenant's own cl - start_stripe_connect_onboarding: Returns a Stripe Connect OAuth URL the operator opens in a browser to connect their existing Stripe account. Uses Standard accounts via OAuth — the tenant connects their own Stripe account (with their - generate_pay_now_link: Creates a Stripe Checkout Session for an unpaid invoice on the tenant's connected Stripe Express account. Returns the Stripe-hosted URL the customer opens to pay by card. Payment is recorded automatic - disconnect_stripe: Disconnects the tenant from Stripe Connect. Marks the local connection as disconnected; does NOT delete the Stripe Express account on Stripe's side (tenant retains ownership and can re-connect at any - get_client_portal_finance_view: Returns the four-panel client portal Finance tab data for the given client: outstanding cents, past invoices (with payable flag), payment history, credit balance + recent entries, and whether the cred - list_client_invoices: Lists invoices for a specific client, ordered by issued_at descending. Optional status filter. Default page size 50, max 200. Money fields returned as integer cents. Read-only. - list_client_payments: Lists payments recorded against a specific client's invoices, ordered by payment_date descending. Money fields returned as integer cents. Read-only. - request_statement_for_client: Returns the on-demand statement aggregate for a client over a date range — the same data the client sees in their portal Finance tab when they pick a period. Includes opening balance, in-period invoic - set_client_invoicing_cadence: Sets the invoicing cadence for a specific client. Controls what happens when a job for this client is completed. - get_late_fee_config_for_client: Returns the resolved late-fee config for a client — mode (none|interest|flat_fee), flat fee amount (cents), interest rate (bps), grace period days, recurrence (once|monthly), and the source of the mod - preview_late_fees_for_invoice: Dry-runs the late-fee application for an invoice and returns what WOULD happen — same response shape as apply_late_fees_for_invoice but with zero side effects. Useful for previewing the daily-sweep be - apply_late_fees_for_invoice: Applies the owed late fee to an overdue invoice per the resolved config (use get_late_fee_config_for_client to inspect). Creates a NEW draft invoice anchored to the original via late_fee_for_invoice_i - list_late_fee_invoices: Returns every late-fee invoice anchored to a given original invoice, ordered by period_number ASC. Empty list = no late fees have been applied yet to that invoice. - create_payment: Records a payment received against an invoice. `amount_cents` is INTEGER CENTS. Payment does not auto-update invoice status — that must be done separately if the invoice is fully paid. `payment_date` - cancel_pending_operation: Cancels a pending operation in `pending` or `staged` status. After approve_send_operation has fired, the operation is `approved_and_sent` and cannot be cancelled — that's a separate withdrawal/voiding - list_proposals: Lists proposals for the tenant, with optional filters. Returns proposal header info including status, client, site, and dates. Excludes soft-deleted rows by default. - get_proposal: Gets a single proposal with full detail: header, all lines (with service/frequency names), and acceptance records. - preview_proposal_investment: Preview the HONEST, frequency-aware investment summary for a proposal BEFORE sending — the SAME figures the operator view, the signed-agreement PDF, and the client accept page render (one shared calcu - list_proposal_acceptances: Lists proposal acceptance records for audit/history. Returns core fields by default; set `include_snapshot=true` to include the full proposal_snapshot JSONB (large). Audit fields include ip_address, u - create_proposal: Creates a new proposal in `draft` status for a client at a specific site. After creation, add lines with add_proposal_line. Auto-assigns the next proposal_number for the tenant. - update_proposal: Updates the header fields (intro message / notes, valid_until date) on a draft proposal. Only allowed when proposal status is `draft` — same constraint as update_proposal_line. For line item changes u - add_proposal_line: Adds a line item to a draft proposal. Each line links a service (and optionally a frequency) with pricing in integer cents. Only allowed when proposal status is `draft`. - update_proposal_line: Updates a proposal line's price, description, quantity, or display order. Only allowed when the parent proposal is in `draft` status. - remove_proposal_line: Soft-deletes a line from a draft proposal (sets `deleted_at` on the line row). Only allowed when proposal status is `draft`. - record_proposal_acceptance: Records that a proposal has been accepted. Creates a `proposal_acceptances` record (immutable legal evidence) and updates the proposal status to `accepted`. For email-reply acceptance, captures the li - bulk_archive_proposals: Soft-deletes multiple proposals in a single call. Accepted proposals are IMMUTABLE and are skipped (not archived). Cascade-cancels any associated pending/staged operations for archived proposals. - clone_proposal_with_amendments: Supersedes a sent proposal with an amended copy in one atomic call. Archives the source, creates a new draft with the same client/site, copies all lines (applying optional price/quantity/description/f - approve_send_operation: Approves a staged send operation and immediately sends the email to the recipient with a portal-link CTA. Generic dispatcher — branches on `pending_operation.operation_type` to the right artifact-spec - get_pending_operation: Read-only inspection of a staged operation. Returns the operation's current state, the email subject/body that will be sent, the attachment path, the signing_token, and the related entity details. The - list_pending_operations: List staged or in-flight operations for the current tenant. Default returns the most recent 20 staged operations. Filter by status (`staged`, `approved_and_sent`, `cancelled`) or entity_type. - list_expired_pending_operations: List pending operations that lapsed past their TTL without being confirmed or approved — i.e. staged sends that silently died. Returns swept rows (status='expired') plus pending rows already past expi - get_email_delivery_status: Returns the email delivery status for an outbound communication: pending/sent/delivered/bounced/soft_bounced/complained, the chronological Resend webhook event timeline, and (when the entity is a supp - list_recent_bounces: Returns recent bounce and (optionally) complaint events for the tenant — one row per outbound email that failed. Includes recipient, bounce reason from Resend's payload, originating entity (invoice/st - get_audit_log: Returns recent audit log entries for the tenant. Supports filtering by actor, entity, action, and date range (time-window via `from_date` / `to_date` ISO params). The canonical audit timeline across t - get_audit_log_for_entity: Returns all audit log entries for a specific entity in chronological order. The complete timeline for one entity — use for self-diagnosis of unexpected state. Pass include_domain_events:true to ALSO r - assign_job: Assigns a contractor to a job. Runs the compliance gate (SMA signed, insurance current, capability matches service, availability). On a hard-gate failure the assignment is blocked and the reason is su - dispatch_job: Transitions an assigned job from `scheduled` to `dispatched`. Sets `work_order_sent_at = NOW()`. Emits `job.dispatched`. Generic dispatch — for the email-bearing work-order send, use the propose_send_ - approve_job: Approves a completed (or partial) job — admin sign-off step that downstream invoicing consumes. Sets `status='approved'`, `approved_at=NOW()`, `approved_by=actor`. Emits `job.approved` with the full p - reschedule_job: Moves a single job to a new date and captures a reason. Validates the new date shape and that the job is not in a terminal status (completed/approved/invoiced/paid/cancelled). Sets `is_rescheduled=tru - cancel_job: Cancels a job and captures a reason. Terminal status transition — cancelled jobs are not respawned by the engine. Emits `job.cancelled`. - decline_job: Contractor declines an assigned job after acceptance. Captures `decline_reason` and clears `contractor_id` so the job returns to the unassigned queue. Status transitions to `declined`. Emits `job.decl - request_schedule_change: Contractor-side request to reschedule a job. Gated by the `scheduling.contractor_portal.can_change_schedule` registry setting (no | request_only | yes), falling back to the legacy `tenants.scheduling_ - list_schedule_change_requests: Lists schedule change requests (client portal, contractor portal, field triage, request_schedule_change) with status, requested/effective dates, and linked job context. Default filter is status='pendi - approve_schedule_change_request: Operator approves a pending schedule change request: atomically moves the job to the requested date (or `override_date`), marks the request 'approved' with actioned_at/actioned_by, links the audit tra - decline_schedule_change_request: Operator declines a pending schedule change request: marks it 'declined' with the reason in actioned_note, sets actioned_at/actioned_by, and emits schedule_change_request.actioned. The job is NOT touc - list_unassigned_jobs: Returns unassigned jobs needing dispatch (`status='scheduled'` OR `status='declined'`) with `contractor_id IS NULL` — the admin dispatcher's unassigned queue. Declined jobs re-enter this queue for re- - list_jobs_for_contractor: Returns all jobs assigned to a specific contractor within a date range, optionally filtered by status. Contractor-portal-style view (no client legal scope, no client rate). Sorted by scheduled_date as - list_jobs_for_client: Returns jobs for a specific client (across all their sites) within an optional date window. Without date_from/date_to it returns the client's jobs ordered by scheduled_date (earliest first, capped at - get_contractor_schedule: Returns a contractor's own upcoming schedule: jobs by date plus aggregate stats. Excludes cancelled and terminal (completed/approved/missed) jobs. No client legal scope, no client rates. - suggest_contractors_for_job: Returns the contractors that PASS the compliance gate for this job's service (`candidates`), the contractors that FAIL it (`blocked` — each with the failure reason, including contractors with no capab - bulk_assign_jobs: Assigns N jobs to one contractor in a single call. Compliance gate runs once per (contractor, service_id) — jobs that fail capability or other gates are returned in the `failed` list with their reason - bulk_reschedule_jobs: Moves N jobs to a single new date with the same reason. Each job's lifecycle is gated independently — completed/approved/invoiced/paid/cancelled jobs are returned in the `failed` list. Emits one `job. - get_dispatcher_view: Composite — returns the canonical ScheduleView for the operator dispatcher: jobs bucketed into unassigned/today/upcoming/completed/cancelled, contractors-on-leave list, and aggregate stats (total / as - regenerate_csl_schedule: Permanently changes a contract service line's frequency (cadence) and/or recurrence inputs (day_of_week, week_of_month, anchor_date), then regenerates its future undispatched jobs. Two-phase: call wit - create_recurring_service: Set up a recurring service for a client at a site — anything from a simple fixed cadence to a multi-phase PROGRAM with intervals that change over the year. Creates a contract service line + a material - run_job_spawning: On-demand preview and execution of the recurring-job spawning engine. Two-phase: call with dry_run=true (default) to preview what jobs would be created, then dry_run=false with the returned confirm_to - report_bug_to_biloh: Report, file, submit, log, raise, or flag a bug, defect, or issue with the Biloh platform — the CANONICAL WRITE TOOL for filing a bug report. When your intent is 'report a bug' / 'file a bug', call TH - request_tool_to_biloh: Request, propose, ask for, or submit a NEW tool to the Biloh platform — the canonical write tool for filing a tool request (list_my_reported_issues is the read-back of what you already filed; it does - upgrade_tool_to_biloh: Suggest, propose, file, submit, or log an upgrade or improvement to an EXISTING Biloh tool that works correctly but could communicate or structure itself better — the canonical write tool for filing a - list_my_reported_issues: Read back the bugs, tool requests, and tool upgrades THIS tenant has filed via report_bug_to_biloh / request_tool_to_biloh / upgrade_tool_to_biloh, with their current triage status. Tenant-scoped — re - send_operator_report_email: Send a report email from the platform to the CONFIGURED operator address. The recipient is read ONLY from the tenant setting `notifications.operator_report_email` — you cannot pass an arbitrary recipi - list_settings: Lists platform settings registered for this tenant with current values, default values, tier status, and metadata. Filterable by category, scope, and full-text search across keywords + descriptions. - get_setting: Reads one platform setting's current value + metadata for this tenant. Returns the registered definition, the default value, the `previous_value` (if any), `tier_status` (enabled or upgrade_required), - update_setting: Updates one platform setting's value for this tenant. Writes audit_log + emits `settings.updated` event. Reversible via revert_setting (architect persona). Supports optimistic-concurrency via `lock_ve - list_setting_history: Returns the chronological audit history for one platform setting: every `setting.changed` and `setting.reverted` event with actor, timestamp, before/after values, and reason. Limit defaults to 20, max - configure_setting: Composite (front-of-house). Set a platform setting to a new value. Audit-logged + reversible via revert_setting. Use this as the default for natural-language settings changes; use update_setting direc - get_session_context: ⚡ READ ME FIRST ⚡ — Returns the full operational context for this tenant: business identity, your persona + role, key conventions, current state snapshot, and pointers to deeper reference. Call this b - search_tools: Find the right MCP tool by intent — returns a ranked, persona-scoped shortlist (name + one-line summary + category) so you do not have to scan the full catalogue or guess a name. - list_marketing_content: Lists the tenant's marketing-site content for one kind (category | industry | case_study | page | help_article | testimonial | site_config). Returns published rows by default; pass include_unpublished - upsert_marketing_content: Creates or updates one marketing-site content row (kinds: category | industry | case_study | page | help_article | testimonial | site_config). Insert vs update is resolved by payload.id, else by the k - set_marketing_content_published: Publishes or unpublishes one marketing-site content row (kinds with a published flag: category | industry | case_study | page | testimonial). - create_marketing_upload_link: Generates a short-lived, SINGLE-USE browser upload link for a website photo. Give the link to the user — they tap it on their phone, pick the photo, add a caption, and it lands in the website media li - list_marketing_assets: Lists the tenant's website photo library (tenant_media_assets), newest first. Each item carries public_url (what attach_marketing_asset places on the site), kind, alt_text, and upload time. - attach_marketing_asset: Places a library photo onto the website by writing its public URL onto a marketing content row. - get_branding_kit: Returns the tenant's branding kit: every asset slot (logo_full, logo_white, logo_icon, favicon, email_header, pdf_header, social_banner, letterhead) with its status, required format/dimensions, and pu - create_branding_upload_link: Generates a short-lived, SINGLE-USE browser upload link that lands a file directly in a branding-kit SLOT (replacing the current asset at its stable path). Because every surface reads the kit, one upl - get_my_subscription: Returns the current tenant's subscription status, plan, trial countdown, billing details, and the active plan's catalog price — price_monthly_cents, price_annual_cents, currency (AUD), tax_inclusive ( - get_my_entitlements: Returns the calling tenant's EFFECTIVE feature entitlements resolved from its active subscription plan: the per-plan feature flags (custom_branding, api_access, priority_support, white_label, ai_enabl - set_tenant_plan_price_override: Test-gated, tenant-scoped subscription-plan price override for autonomous, fully-reversible price-change testing inside a dogfood tenant. Sets (or clears with price_cents:null) a GST-inclusive overrid - set_tenant_feature_flag_override: Test-gated, tenant-scoped entitlement feature-flag override for autonomous, fully-reversible entitlement-gating testing inside a dogfood tenant. Sets (value:true/false) or clears (value:null → fall ba - create_billing_portal_session: Creates a Stripe Billing Portal session for the current tenant. Returns a URL to redirect the operator to manage their subscription (update payment method, switch plan, cancel). Billing-exempt — works - get_compliance_document_for_review: Returns a compliance document's metadata, readable content (text and/or images delivered in-band), and a short-lived signed URL (15 min). The reviewing agent can read the document directly from this t - upload_compliance_document_from_agent: Uploads a compliance document (insurance certificate, etc.) on behalf of a contractor via the agent chat. Accepts the file as base64, validates integrity, stores it in Supabase Storage, creates a pend - propose_send_work_order: Stages a work-order send. Accepts EXACTLY ONE of `job_id` (single job), `job_ids` (a set of jobs for the same contractor, max 100), or `contract_service_line_id` (an ongoing recurring series) — the wo - propose_send_credit_note: Stages a credit-note send for operator approval. First leg of the three-leg send chain (propose → confirm → approve). Resolves the recipient email from the linked client's billing_email if not supplie - approve_send_statement: Approves a staged statement send and dispatches the email to the client immediately. The statement transitions from draft → sent, message_id + recipient_email + sent_at are persisted, statement.sent i - propose_send_invoice: Proposes sending an invoice to the client. Creates an `mcp_pending_operations` row — the send is staged (stored status value 'pending') and MUST be confirmed via `confirm_pending_operation`, then appr - confirm_pending_operation: Confirms a previously staged operation (leg 2 of 3 in the propose → confirm → approve send chain). Behaviour depends on operation_type: - render_artifact_pdf: Renders a tenant artefact (proposal, signed agreement, work order, ongoing-series work order, invoice, quote, statement, receipt) as a PDF, stores it in Supabase storage scoped to the tenant, and retu ## Auth MCP requests authenticate via a tenant-scoped Personal Access Token (see /mcp for current connection instructions). A PAT issuance UX is under active development; until that lands, tenants generate tokens through their administrator surface. ## Contact hello@biloh.com.au — general privacy@biloh.com.au — privacy support@biloh.com.au — support