bexio API from Make and Zapier: what the ready-made modules cannot do
Make and Zapier offer bexio as a ready-made app: fill in a few fields and the invoice lands in your accounting. Yet the community forums of both services hold questions about bexio dating back to 2023 that never got solved, because the module lacks a field or an endpoint. I went through these threads and compared them with the official bexio API documentation. This guide shows, case by case, where the forum got stuck and which field of the bexio API solves it. It describes the modules as the people asking describe them; it is not based on my own experience with Make or Zapier.
Where the eight cases come from
The cases come from the public forums community.make.com and community.zapier.com, questions asked between 2023 and 2025. Each case is linked below. “Unsolved” means: the thread has no answer confirmed by the person asking, or the answer points to support. Several people report the same pattern, sometimes months apart. The solution through the API is backed by the documentation in every case; the paths appear there exactly as written.
Case 1: several line items on one invoice
The most common problem. In Make, someone wants to write several line items into one bexio invoice; the module rejects the list, and “Update Invoice” offers no line item at all. In Zapier the same thing fails with a Shopify order containing several products, with a WooCommerce order through a detour with a loop and temporary storage, and with a Payrexx payment, where the error says the list of amounts is not the same length as the list of items; what remains is a draft without line items and a total of 0.
In the API this is not a special case. POST /2.0/kb_invoice accepts an array positions,
and the documentation states explicitly that position types can be mixed: KbPositionCustom
for free lines, KbPositionArticle for items from the catalogue, plus text, subtotal,
discount and page-break positions. An invoice with two lines looks like this:
{
"contact_id": 14,
"user_id": 1,
"mwst_type": 0,
"mwst_is_net": true,
"positions": [
{ "type": "KbPositionArticle", "article_id": 3, "amount": "2", "unit_price": "45.00", "tax_id": 4 },
{ "type": "KbPositionCustom", "text": "Shipping", "amount": "1", "unit_price": "9.00", "tax_id": 4 }
]
}
bexio recommends at most 150 positions when creating a document; further lines are appended
afterwards with POST /2.0/kb_invoice/{document_id}/kb_position_article or
…/kb_position_custom. Shipping and discount are thus ordinary lines, no workaround needed.
Case 2: document number on quotes
A Zapier user cannot create a quote:
bexio demands document_nr, the action has no field for it; a second person affected turns
up in the same thread. Another
cannot find a quote by its number,
although the same number returns a hit in a different tool.
The documentation for POST /2.0/kb_offer explains the rule: document_nr must not be set
when automatic numbering is active in bexio, and it is required when automatic numbering is
switched off. A module without this field therefore only works with automatic numbering.
Anyone keeping their own numbers sets them through the API. Searching goes through
POST /2.0/kb_offer/search with document_nr as the search field:
[{ "field": "document_nr", "value": "AN-00001", "criteria": "=" }]
Without criteria, bexio searches with “like”, i.e. partial matches; for a number, = is
the safe choice. The same search fields exist for invoices under POST /2.0/kb_invoice/search.
Case 3: tax rate per line item
An invoice arrives in bexio with 7.7% instead of 8.1%, and the tax rate cannot be chosen in the module. Zapier confirms a bug report in the thread; the workaround is to store the rate on the product in bexio.
In the API every position carries its field tax_id. The valid values come from
GET /3.0/taxes?types=sales_tax&scope=active; this is exactly the call the documentation
recommends, because only active sales taxes are allowed on quotes, orders and invoices. The
response lists id, code, value and the years of validity for each rate. A service reads
this list once and picks the tax_id by percentage instead of hard-coding a number that
becomes wrong at the next rate change.
Case 4: reference for payment matching
Someone creates invoices from a Google Sheet and wants to write the 27-digit reference number into the reference field so that bexio matches incoming bank payments automatically. Zapier files a feature request; no date is given.
The invoice in the API has two reference fields. reference is free text on the document.
api_reference, according to the documentation, can only be read and edited through the API
and is meant to store references to other systems, such as the shop’s order number or the
payment provider’s payment ID; it is also a search field of POST /2.0/kb_invoice/search.
The response for an invoice also contains qr_invoice_id. A field for setting the reference
of the QR payment part yourself is not described in the documentation.
Anyone who gets the payment reported by a payment provider anyway does not need bank matching
for it: POST /2.0/kb_invoice/{invoice_id}/payment books the payment directly onto the
invoice with date, value and bank_account_id. The payment then shows on the invoice in
bexio, and nobody sends reminders to customers who paid long ago.
Case 5: user in time tracking
Time entries from a Google Sheet should belong to the right employee in bexio. In the Zapier module the user ID cannot be set; the field gets filled with a contact, and the person asking finds no way out.
POST /2.0/timesheet requires user_id as a mandatory field, along with client_service_id
for the service, allowable_bill for “billable” and an object tracking, either as a
duration (type: duration with date and duration) or as a time range (type: range).
Users come from GET /3.0/users, services from GET /2.0/client_service. Contact and project
are optional (contact_id, pr_project_id). An entry of one hour and forty minutes:
{
"user_id": 1,
"client_service_id": 1,
"allowable_bill": true,
"contact_id": 2,
"tracking": { "type": "duration", "date": "2026-11-04", "duration": "01:40" }
}
Case 6: PDF of a quote
A Make user wants to archive quotes as PDF in DocuWare. There is a module for invoices but none for quotes; the attempt with an HTTP call yields a PDF that will not open. The only reply points to HTTP basics.
GET /2.0/kb_offer/{quote_id}/pdf returns the document, with or without letterhead
(logopaper). The point where the person failed: the response is not a PDF but JSON with the
fields name, size, mime and content, and content holds the file Base64-encoded. Only
after decoding do you have a valid PDF file. The same applies to invoices
(/2.0/kb_invoice/{invoice_id}/pdf) and orders (/2.0/kb_order/{order_id}/pdf).
Case 7: detecting changed invoices
According to one forum member, the Make trigger “Watch Invoices” delivers no records when an invoice is merely changed. One person replying suspects a bug in the module, a second suggests searching instead.
The API offers the search field updated_at with comparison criteria for this. A service
remembers the timestamp of its last run and asks:
[{ "field": "updated_at", "value": "2026-11-04 06:00:00", "criteria": ">" }]
at POST /2.0/kb_invoice/search?order_by=updated_at_desc. The time format matches what bexio
returns in updated_at. New and changed invoices thus show up the same way, for example a
status change to “paid”.
Case 8: invoice from an order
A Shopify order becomes a bexio order in Make; the invoice from it is to be created by an HTTP call because there is no module for it. The call fails with status 415, while the same call works in Postman. Make support confirms a known issue in the thread and passes it on to development, without a date.
The endpoint is POST /2.0/kb_order/{order_id}/invoice. The body is optional: if it is
missing, bexio takes over all positions of the order; otherwise positions names the desired
lines with id, type and amount. Status 415 means the server does not accept the content
type of the request; the documentation requires Accept: application/json and JSON as the
body. A dedicated service sets the headers itself and does not depend on how an intermediary
passes them on.
The eight cases at a glance
| Case | In the forum | In the bexio API |
|---|---|---|
| Several line items | list rejected, draft with total 0 | positions in POST /2.0/kb_invoice, mixed types |
| Document number | required field missing, search without hits | document_nr, search with criteria: "=" |
| Tax rate | not selectable, wrong rate | tax_id per position, list from /3.0/taxes |
| Reference | field missing, feature request open | reference, api_reference, payment via …/payment |
| Time tracking | user cannot be set | user_id in POST /2.0/timesheet |
| Quote PDF | no module, unreadable file | /2.0/kb_offer/{id}/pdf, decode content from Base64 |
| Changed invoices | trigger does not react | search on updated_at with > |
| Invoice from order | no module, status 415 | POST /2.0/kb_order/{id}/invoice |
On top of that comes a risk no field can fix: a Zapier user reports that bexio locked the client ID of the Zapier app and his connection stopped with it. Anyone connecting through a third-party app depends on its approval; your own app in the Developer Portal depends only on yours. How to create one is in the guide Create a bexio API token, the sign-in via OAuth 2 in the guide Connect the bexio API to WordPress.
When the direct connection pays off
For a contact from a form, the ready-made modules are usually enough. As soon as invoices with several lines, your own numbers, tax rates, time entries per employee or PDFs come into play, the detour through the intermediary platform costs more time than it saves: every missing field turns into a forum thread with no end.
An interface that talks to the bexio API directly is something I build for a fixed price: you tell me the source system and the workflow, I define the scope on your real documents, the connection runs on your own infrastructure without a subscription with a third party, with retries on errors and a log that shows what was transferred. For HubSpot the connection already exists: bexio ↔ HubSpot turns a won deal into a quote or invoice with line items and reports the payment status back. For everything else: Contact, with the source system and what is done by hand today.