Skip to main content
The Fynn MCP server implements the Model Context Protocol and makes the most important Fynn features directly accessible to AI assistants like Claude. Instead of opening a user interface, you describe what you need, and the assistant calls the appropriate tools. Typical use cases:
  • 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

For the sandbox environment, replace the host with 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

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

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 the invoice: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.
An approved invoice is legally binding and immutable. The manual approval cannot be bypassed from the MCP server.

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.
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 imageBlock:
Pass the returned 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.