InvoiceIQ documentation
InvoiceIQ turns supplier invoices into coded, verified, ERP-ready vendor bills. This page covers the product, how to connect it to Claude, ChatGPT or another MCP client, how sign-in works, every tool the connector exposes, how organizations, roles and the audit log constrain what a connected assistant can do, and where the legal documents and support live. Updated 2026-09-07.
What InvoiceIQ is
Upload a supplier invoice PDF and InvoiceIQ runs it through an 11-step pipeline: text extraction, vision extraction for scanned pages, header parsing, line items, vendor identification, GL coding (vendor rule, then lookups, then AI), verification and formatting. If the invoice names a purchase order, the PO and its goods receipts are read from the connected ERP and the match policy runs (2-way, 3-way or custom). A verified invoice can be posted as a vendor bill; every attempt is logged, and a second post of the same invoice number is refused and names the bill that already exists.
Connected to an AI assistant, you ask for the same things in plain English: list what arrived this week, open one invoice to see its extracted header and GL-coded lines, ask why a line was coded to an account, check the match report against the purchase order and receipts, run a spend question across your invoice history, upload a PDF straight from the conversation and poll its processing status. When an invoice is complete and matched, ask the assistant to post it: InvoiceIQ shows the exact bill it is about to create and posts only after you confirm.
Everything happens inside your organization and your role, enforced in the database, and every tool call is written to your organization's audit log. InvoiceIQ works with NetSuite (vendor bills, purchase orders, item receipts) and with a built-in demo ERP.
Connect InvoiceIQ to an assistant
The connector is a remote MCP server: https://invoiceiq.analytos.ai/mcp (streamable HTTP, OAuth 2.1, dynamic client registration). One URL serves every user and organization; there is nothing to install and no API key to create.
- Claude (any plan): claude.ai, Settings, Connectors, Add custom connector. Paste
https://invoiceiq.analytos.ai/mcp, leave the client ID and secret empty, click Connect, then sign in with your InvoiceIQ account when the InvoiceIQ page opens.
- ChatGPT: Settings, Connectors, Advanced, enable Developer Mode, add the connector with the same URL and sign in.
- Any other MCP client that supports streamable HTTP with OAuth 2.1 and PKCE (for example MCP Inspector): point it at the URL above; it registers itself automatically.
You need an InvoiceIQ account in your organization first (your InvoiceIQ administrator creates it). An ERP connection is optional; without one the built-in demo ERP is used.
Signing in (OAuth)
- The client reads
/.well-known/oauth-protected-resource/mcp and /.well-known/oauth-authorization-server (OpenID Connect discovery is at /.well-known/openid-configuration) and registers itself at /register. No pre-shared client ID is needed.
- Your browser opens InvoiceIQ's Connect to InvoiceIQ page. It names the client and lists what it will be able to do, for example "read invoices, upload invoices, read coding rules, post vendor bills (with confirmation), run spend searches".
- Enter your InvoiceIQ e-mail and password and click Sign in and allow. The client receives an authorization code and exchanges it at
/token with PKCE (S256 is required).
- The client holds an access token (60 minutes by default) and a rotating refresh token (30 days by default). It acts as you, inside your organization and role, for as long as its token is valid. Tokens can be revoked at
/revoke.
The scopes a client can request map to the tools below: invoices:read, invoices:write (upload), coding:read, bills:post and search, plus openid, email and profile for identity. A web-app login token is never accepted by the MCP server and an MCP token is never accepted by the web API; the two are separate.
Tools
The connector exposes 18 tools. Every call runs as the signed-in user, inside that user's organization and role, and is written to the audit log. Access is what the tool's MCP annotations declare (readOnlyHint / destructiveHint); Scope is the OAuth scope the connected client must hold; Permission is the role permission the user must have (see Organizations and roles).
| Tool | Title | Access | Scope | Permission | What it does |
list_invoices | List invoices | read-only | invoices:read | invoices:read | List processed invoices in your organization (your own unless your role can read all). Filters: status, vendor substring, ISO date range, limit (max 200). |
get_invoice | Get invoice | read-only | invoices:read | invoices:read | Header, coded line items and the latest match result for one invoice (by invoice_id). |
upload_invoice | Upload invoice PDF | write | invoices:write | invoices:create | Uploads a PDF (base64) and starts the extraction/coding/verification pipeline. Returns the new invoice_id; its processing status is reported by get_pipeline_status. |
get_pipeline_status | Get pipeline status | read-only | invoices:read | invoices:read | Processing status/progress of an uploaded invoice (session id = invoice_id). |
search_invoices | Search invoices (natural language) | read-only | search | intelligence:read | Answers a plain-English question about invoice spend by running a read-only, validated SQL query over the analytics tables of your organization. |
list_coding_rules | List coding rules | read-only | coding:read | coding:read | Vendors on the coding engine with their active rule (plain-English rule, signal, validation state). Optional vendor_id filter. |
explain_coding_decision | Explain a coding decision | read-only | coding:read | coding:read | Why a line item was coded the way it was: method, reasoning, business rule, and the vendor's active rule. |
get_match_report | Get match report | read-only | invoices:read | invoices:read | Match reports (2-way/3-way checks, policy, outcome) for an invoice. Matching runs when a bill is posted, so an invoice that has never been posted has no report yet; there is no separate match step to run. |
post_bill | Post vendor bill (destructive) | write, destructive | bills:post | bills:post | Post a completed invoice to the ERP as a vendor bill. DESTRUCTIVE and not reversible here. Without confirm=true it posts nothing and returns a preview of the exact bill with a confirmation_required result; with confirm=true it posts that bill. The match policy (2-way/3-way) runs as part of posting and the ERP refuses bills whose PO is not billable (e.g. goods not received); the result reports the match outcome. |
get_kpi_summary | Get KPI summary | read-only | invoices:read | invoices:read | Your dashboard numbers (invoices processed, lines classified, average confidence, pending, needs attention) plus organization-wide KPIs and the top vendors. |
list_posting_log | List posting log | read-only | invoices:read | erp:read | Every attempt to post a bill to the ERP, most recent first: who, which invoice, outcome, bill id, match policy. Optional invoice_id filter. |
list_purchase_orders | List purchase orders | read-only | invoices:read | erp:read | Purchase orders in the connected ERP: number, vendor and total. |
get_purchase_order | Get purchase order | read-only | invoices:read | erp:read | One purchase order with its lines, goods receipts and the bills already raised against it. |
list_posted_bills | List posted bills | read-only | invoices:read | erp:read | Vendor bills posted from InvoiceIQ, most recent first, with their lines and match outcome. |
list_billing_rules | List billing rules | read-only | coding:read | rules:read | Billing composition rules grouped by decision: where charges post (Items/Expenses tab), which lines are billed, what the bill is drawn from. Optional kind filter. |
list_posting_fields | List posting fields | read-only | coding:read | rules:read | The registry of bill header/line fields (built-in plus custom) that header rules can set. |
list_header_rules | List header rules | read-only | coding:read | rules:read | Bill-header rules (the Global Billing Rules page): every version with its plain-English rule, field and status. Global set by default; pass vendor_id for a vendor's overrides. |
get_cdm_schema | Get data model | read-only | coding:read | rules:read | The canonical data model (CDM Objects page): documents, canonical objects, fields and what each field is linked to in the connected ERP. |
16 tools are read-only. upload_invoice writes (it creates an invoice record and starts processing). post_bill writes and is destructive: it posts to the ERP and refuses to do so without confirm=true (see Posting a vendor bill below).
Arguments and example prompts
- list_invoices (
status, vendor, date_from, date_to, limit) - "Show me my recent invoices"; "List invoices from Acme Utilities that still need review"
- get_invoice (
invoice_id*) - "Open invoice INV-1001 and show me how each line was coded"
- upload_invoice (
file_base64*, filename*) - "Upload this invoice PDF and tell me when it has finished processing"
- get_pipeline_status (
session_id*) - "Is the invoice I just uploaded done processing?"
- search_invoices (
query*) - "How much have we spent with Meridian Equipment, by GL account?"; "Which vendors billed us more than $5,000 this quarter?"
- list_coding_rules (
vendor_id) - "Which vendors have an active coding rule, and what does the Acme rule say?"
- explain_coding_decision (
line_item_id*) - "Why was the first line of INV-1001 coded the way it was?"
- get_match_report (
invoice_id*) - "Show me the 3-way match report for ME-8801"
- post_bill (
invoice_id*, confirm) - "Post invoice ME-8801 as a vendor bill (ChatGPT shows the preview, you confirm, then it posts)"
- get_kpi_summary (no arguments) - "How many invoices did we process and what needs attention?"
- list_posting_log (
invoice_id, limit) - "Show the last 10 bill postings and whether they succeeded"
- list_purchase_orders (
limit) - "Which purchase orders are open?"
- get_purchase_order (
po_number*) - "Open PO1001 and show what has been received and billed"
- list_posted_bills (
limit) - "List the vendor bills we posted this week"
- list_billing_rules (
kind) - "What are our billing rules for freight and sales tax?"
- list_posting_fields (no arguments) - "Which bill fields can header rules set?"
- list_header_rules (
vendor_id) - "What global header rules are active, and does Acme override any?"
- get_cdm_schema (no arguments) - "Show me the data model and which fields map to NetSuite"
Arguments marked * are required.
Resources
The server also publishes 4 read-only resources. All of them are application/json data; the connector returns no UI components, so there is nothing to render and no content security policy to declare.
| URI | Title | Content type | Description |
invoiceiq://vendors | Vendors | application/json | Vendors configured on the coding engine |
invoiceiq://gl-accounts | GL chart of accounts | application/json | The organization's GL chart of accounts |
invoiceiq://match-policies | Match policies | application/json | 2-way/3-way/custom match policies |
invoiceiq://capabilities | ERP capability manifest | application/json | What the active ERP can and cannot do |
Posting a vendor bill: confirmation is required
post_bill is the one destructive tool, and it is built so that an assistant cannot post by accident.
- Only an invoice whose status is
completed can be posted; anything else returns invalid_state.
- A call without
confirm=true never posts. It returns the error confirmation_required carrying a preview of the bill: invoice_id, vendor, invoice_number, po_number, total_amount, tax_amount, line_count and the lines (GL code and name, class, department, amount, quantity, unit rate, memo). The audit log records the call with status confirmation_required.
- The assistant shows you that preview and asks. Only when you confirm does it call again with
confirm=true.
- On the confirmed call the match policy (2-way, 3-way or custom) runs as part of posting; the ERP refuses bills whose purchase order is not billable (for example goods not yet received). The result reports
success, bill_id, url, error, posting_audit_id and match_outcome.
Posting needs the bills:post scope on the token and the bills:post permission on your role (clerk, approver, admin and owner have it; viewer does not).
Errors
Tool errors are structured JSON, never stack traces: {"error": {"code": "...", "message": "..."}}. Codes: not_found (also used for records that belong to another organization or another user, so existence is never leaked), forbidden (the token lacks a scope or your role lacks a permission), confirmation_required (post_bill without confirmation; carries the preview), invalid_argument, invalid_state, query_rejected (search_invoices refused the generated query), post_failed (the ERP rejected the bill; see the posting log), rate_limited and internal_error (with a reference id for support).
Organizations and roles
Every record belongs to exactly one organization and the database enforces that boundary with row-level security; a connected assistant sees only your organization, and an id from another organization returns not_found.
Inside the organization your role decides what you can do. Roles, in ascending order: viewer, clerk, approver, admin, owner.
| Role | What a connected assistant can do |
| viewer | Every read-only tool, across the whole organization. Cannot upload or post. |
| clerk | Reads and uploads, and can post bills, but only for their own invoices: list_invoices returns the clerk's invoices and other users' invoice ids return not_found. |
| approver | Everything a clerk can, for every invoice in the organization. |
| admin | As approver; additionally manages users and organization settings in the web app. |
| owner | Every permission. |
The Permission column of the tool table names the exact permission each tool checks. A call that fails the check is refused with forbidden and recorded in the audit log as denied.
Audit log
Every tool call is written to the organization's audit log, the same log the web application's audit trail uses, with the outcome (ok, error, denied, rate_limited or confirmation_required), the user id, e-mail and role, the connected client's id, a summary of the arguments (uploaded file contents are recorded only as a byte count), and a short summary of the result or the error. Failed authorization and rate-limit refusals are logged too.
Rate limits
Limits are per organization: 120 tool calls per minute across all tools, and additionally 20 per minute for the heavy tools upload_invoice, search_invoices and post_bill (the defaults; a deployment can change them). A refused call returns rate_limited; wait and retry.
Trying it out
The sample invoices used in the walkthroughs and in reviews are INV-1001 from Acme Utilities (a non-PO invoice with four utility lines coded by the Acme vendor rule) and ME-8801 from Meridian Equipment (a PO invoice against PO1001, 3-way matched and postable). Prompts that exercise the connector end to end:
- "Show me my recent invoices"
- "Open invoice ME-8801 and show how each line was coded"
- "Why was the first line of INV-1001 coded the way it was?"
- "Show the match report for ME-8801"
- "How much have we spent with Meridian Equipment by GL account?"
- "Which purchase orders are open?"
- "What are our billing rules?"
- "Post invoice ME-8801 as a vendor bill" (the assistant shows the preview and asks; say "yes, confirm" to post)
Expected refusals: a non-PDF upload, a viewer posting a bill, another organization's invoice id (not_found), and more than 20 posts, uploads or searches in a minute (rate_limited).
Public REST API
The same capabilities are available over REST for integrations that do not use MCP. The curated OpenAPI 3.1 document is served at /openapi-public.json; authenticate with POST /api/v1/auth/login and send the returned token as Authorization: Bearer <token>.
Privacy, terms and support