- Query customer and invoice data in natural language
- Automatically populate offers, including price lookups and images
- Start DATEV cloud exports with a confirmation dialog
Setting up the connection
Endpoint
preview.coreapi.io.
Transport
The server uses Streamable HTTP (MCP specification 2025-03-26). MCP clients that support this transport protocol connect directly to the endpoint above.Authentication
Every request requires two headers:
Create an API key under Settings > API Keys. You find the organization ID in your organization settings.
Configuration example
Most MCP clients (e.g. Claude Desktop) accept a JSON configuration. Here is an example:Permissions
All tools respect the role permissions of the connected user. Anyone who is not allowed to read invoices in Fynn will not receive them through the MCP server either. In that case, the request fails with a clear error message rather than returning empty data.Tool reference
The following 31 tools are available, grouped by functional area.General
fynn_ping
Checks the connection, authentication, and organization context. Returns ok, the organization ID, and a timestamp. Takes no parameters.
Customers
customer_search
Searches for customers by a search term or subscription number.
Returns identity fields only (ID, customer number, display name, type, status). No addresses or contact data.
customer_balance
Returns the debtor balance of a customer. Without a time range, returns the current total balance; with a time range, additionally returns debit/credit sums. Amounts are in cents with currency.
customer_payments
Lists payment transactions for a customer, newest first. Includes date, amount (cents), status, payment method, and document number, but no bank details or IBAN.
Invoices
invoice_search
Searches invoices, credit notes, and cancellations. Filterable by status, document type, customer, and finalization date range. Amounts in cents, dates as ISO-8601.
invoice_reference_chain
Resolves the cancellation/reference chain of a document. Returns the document itself, the referenced original document, and all cancellations/credit notes that reference this document.
invoice_pdf_download
Creates a time-limited download link for the PDF of a document. Returns url, filename, and expiresAt. No binary data is returned.
invoices_zip_download
Bundles the PDFs of multiple documents into a ZIP archive and returns a signed download link. Documents without a PDF are skipped.
Creating and editing invoices
The write invoice tools require theinvoice:write permission. An invoice follows a clear lifecycle: created as a draft, positions added and edited, then finalized or closed. A finalized invoice is immutable and legally binding; finalization therefore requires a manual approval by a human.
invoice_create
Creates a new invoice in draft status. Positions are added separately using invoice_add_position or invoice_add_product_position.
Returns the new draft invoice with header data, positions, and totals (in cents).
invoice_get
Reads an invoice with header data, positions, and totals. The invoice ID can be a UUID or an invoice number.
Returns: header data (id, number, status, type, customer, currencyCode, dueDate, finalizedAt, title, introduction, closing, internalNote), totals (
totals.net/tax/gross in cents), positions, and an editable flag.
invoice_update
Updates the header fields of an invoice that has not yet been finalized. Only fields that are sent are changed; missing fields remain unchanged.
Returns the updated invoice (same structure as
invoice_get).
invoice_add_position
Adds a freely defined position to a draft invoice. Price and tax group must always be specified explicitly.
Returns
{ positionId, invoice } where invoice contains the updated invoice with totals in cents.
invoice_add_product_position
Derives an invoice position from a product in the catalog. Name, unit, and tax group come from the product; the price comes from a flat-fee price plan or an explicit price override.
A price is never guessed. If neither a matching price plan nor a
unitPrice override is provided, the tool rejects the request with a clear error message.
Returns
{ positionId, invoice } (totals in cents).
invoice_update_position
Updates a position on an editable invoice. Only fields that are sent are changed.
Returns
{ positions[], totals } (amounts in cents).
invoice_remove_position
Removes a position from an editable invoice. Remaining positions are renumbered and totals recalculated.
Returns
{ positions[], totals } (amounts in cents).
invoice_close
Permanently closes an invoice without finalizing it. The document receives STATUS_CLOSED and is discarded: no document number, no PDF, no payment. Only possible from draft (STATUS_DRAFT) or STATUS_NEW status.
Returns
{ id, status }.
invoice_finalize
Prepares the finalization of an invoice and creates an approval task in the app inbox. The invoice is not finalized directly.
Because a finalized invoice is legally binding and immutable, finalization follows a two-step process: the AI assistant validates that the invoice is ready to finalize (valid payment method, active customer) and creates an approval task. A human then reviews and approves or rejects it in the app inbox. Only after manual approval is the invoice actually finalized.
A second call for the same invoice returns the existing open task, as long as the invoice has not changed since the first request; the parameters of the original request are kept in that case. If the invoice was edited in the meantime, the old task is dismissed and a new one with a new actionItemId is created. Approval requests expire 72 hours after creation and must then be re-requested.
Returns
{ actionItemId, status: "pending_approval", invoiceId, summary, hint }, where summary contains invoice totals (net, tax, gross in cents), position count and customer data, and hint is a reminder that human approval in the inbox is required. Use pending_action_status with the returned actionItemId to poll for the approval status and the expiry date. Permission: invoice:finalize.
pending_action_status
Queries the status of an approval task, for example one created by invoice_finalize.
Returns
{ id, type, status, createdAt, resolvedAt, expiresAt, invoiceId, executions }. expiresAt is the point in time (UTC) at which the approval request expires; after that, it must be re-requested via invoice_finalize.
Possible values for status: open, snoozed, in_progress, resolved, dismissed.
Each entry in executions contains actionKey (e.g. approve or reject), resultStatus (success or failure), resultMessage, and executedAt. On successful approval, resultMessage includes the assigned invoice number. If approval fails because the invoice was edited after the request or the request has expired, resultMessage explains the reason; the invoice remains unfinalized. Permission: action-item:read.
Creating and finalizing an invoice with AI: a typical workflow
Here is how to create a complete invoice with an AI assistant and send it for approval:1
Create the invoice
Create a new invoice for the desired customer:The response contains the
invoiceId you need for all subsequent calls.2
Add positions
Add positions from the catalog or freely defined positions:Note:
unitPrice always comes from the price plan or an explicit override, never from an estimate.3
Review the invoice
Read the current invoice with all positions and totals before requesting finalization:
4
Request approval
Create the approval task. The invoice is not yet finalized:The response contains
actionItemId, status: "pending_approval", a summary of the invoice totals, and a hint text. Let the user know that the approval is waiting in the app inbox.5
Human reviews and approves
A team member opens the inbox, reviews the invoice, and approves or rejects it. This step takes place exclusively in the app and cannot be bypassed by the AI assistant.
6
Poll for status
Poll for the approval status until the task has been processed:When
status: "resolved" and executions[0].resultStatus: "success", the invoice is finalized; resultMessage contains the assigned document number. When resultStatus: "failure", the invoice was not finalized (for example, because it was edited after the request was created); create a new approval request in that case.Audit
Every tool call through the MCP server is automatically logged: user account, organization, tool name, parameters (without sensitive content), outcome, and execution duration. The audit log is immutable and provides traceability for compliance requirements. Failed and rejected calls are also recorded.DATEV
datev_export_status
Shows whether a DATEV cloud account is connected, and provides a monthly summary of exported and pending postings as well as the last export status.
datev_cloud_export_start
Starts a DATEV cloud export for one or more months. This tool writes data. Without confirm: true, a confirmation request is returned and nothing is executed.
Product catalog
product_tree
Returns the product catalog as a category tree. Each node contains id, name, path, count (number of products), and children. With includeProducts: true, additionally returns a flat product list.
product_search
Searches products in the catalog. Partial match on product name, internal name, and product number.
product_prices
Returns all price plans for a product in complete form. The returned price plan ID is exactly the pricePlan reference that a subscription proposal product entry needs. All amounts are integer cents.
Each price plan includes:
id, name, internalName, status, currency, chargeType, billingInterval, billingFrequency, payInAdvance, proRata, freeUnits, minimumCommitment, and a price block with amounts in cents.
Offers
The offer tools distinguish between read and write operations. Read tools (offer_get, offer_block_types) require offer:read. Write tools (offer_create, offer_update, offer_add_block, offer_update_block, offer_remove_block, offer_upload_image) require offer:write. Accepted or archived offers cannot be modified.
offer_block_types
Lists all supported block types with metadata (whether the block is atomic, whether it is allowed in PDF and document, and which attributes it accepts). With an optional type, also returns a concrete example node that can be passed directly to offer_add_block.
offer_get
Reads the state of an offer efficiently: settings (ID, number, name, status, display language, customer, validity date, acceptance mode, custom variables) and a compact section and block overview. With sectionIndex (and optionally blockIndex), additionally returns the raw JSON body of exactly that section or block.
offer_create
Creates a new offer. All parameters are optional: an offer without a customer is explicitly allowed.
offer_update
Updates the settings of an offer. Only fields that are sent are changed; missing fields remain unchanged.
offer_add_block
Inserts a block into an offer section. Use offer_block_types to get the valid block node format. If the offer has no sections yet, one is created automatically.
offer_update_block
Replaces an existing block completely with the provided Tiptap node.
offer_remove_block
Removes a block from a section; subsequent blocks shift up.
offer_upload_image
Uploads an image for use in offers. Allowed formats: PNG, JPEG, WebP, and GIF (max 5 MB decoded). The MIME type is detected from the image data; the file extension is enforced accordingly. SVG is rejected. The response includes mediaId, url, filename, and a ready-made imageBlock that can be passed directly to offer_add_block.
Creating offers with AI: a typical workflow
Here is how to create a complete offer with an AI assistant:1
Create the offer
Create an empty offer for the desired customer:The response contains the
offerId you need for all subsequent calls.2
Find matching products
Search the product catalog for the desired product:
3
Get the price plan
Load the price plans for the found product:Use the
id of the desired plan as pricePlan in the next step.4
Add a product block
Insert a
subscriptionProposal block with the product and price plan:5
Add text content
Add headings, paragraphs, or tables. Use
offer_block_types to see which block types are available and what a valid node looks like.6
Upload and insert an image
Upload an image and insert it directly. The tool returns a ready-made Pass the returned
imageBlock:imageBlock as block to offer_add_block.All offer tools respect the lifecycle: an accepted or archived offer can no longer be modified. Check the status in advance with
offer_get.