How to integrate with BuchhaltungsButler: Four rate limits on one interface
BuchhaltungsButler has a small surface and an unusual shape: 48 operations, every one of them a POST, and the meaning carried by the path rather than the verb. None of that is what constrains your build. Four published limits do, three of them sit on the write paths this product exists for, and nothing here sends an event to spare you the calls.


Two values authenticate you, the third picks the customer
Connecting takes three values out of your customer’s account: an API Client, an API Secret and an API Key. Almost every description of this system, ours included, calls them three credentials and moves on. The reference does not group them that way, and the difference decides how your multi-account code is shaped.
Under the heading Authentication, the reference is specific about two of them: “Authentication is done by HTTP Basic Auth as specified by RFC 2617. This is to be implemented so that it produces the ‘Authorization’ request header, containing the following value: ‘<Api Client>:<Api Secret>’.” That is the credential pair, and it travels in the header on every request.
The third value gets its own heading, Customer Selection, and a different job: “In order to use the API methods you need to specify the BB customer account you want to manage. This is done by providing the form field ‘api_key’ which contains the target customers api key.”
The API Key does not authenticate anything. It names whose books you are touching, and it travels as a form field on the request rather than in a header.
For a script that serves one customer account that distinction is trivia. For a product with a thousand connected companies it decides the shape of your code: selection does not ride in the header with the credentials, it is payload that has to be correct on every single request. Get it wrong and you do not get a 401, you get someone else’s books.
POST /api/v1/receipts/get HTTP/1.1Host: app.buchhaltungsbutler.deAuthorization: Basic BASE64(api_client:api_secret)Content-Type: application/json{ "api_key": "<the customer's key>" }
The header carries the credential pair, the body carries the selection. The api_key names the customer account and changes on every request that serves a different one.
Both quotations from BuchhaltungsButler’s published reference, sections Authentication and Customer Selection, checked 19 August 2026. The reference also says where the value comes from: the api key “can be found in customers company data settings if customer has registered to api access”.
There is no OAuth redirect anywhere in this, which is why BuchhaltungsButler is one of the seven systems that can be connected without a hosted page at all. Your customer activates access in their own settings, all three values appear together, and they can be submitted from inside your own interface.
Unified authentication is what keeps that from becoming a per-system branch: a redirect on the next system and a database credential on the one after arrive at the same account key, and your code only ever sees the key.
Every one of the 48 operations is a POST
Counted from the published reference: 48 distinct operations, and all 48 are POST. That includes the twelve whose path carries a get segment, the two that delete and the four that update. The HTTP method is not a description of what happens here. The path is.
It is easy to file this under cosmetic and wrong to do so. A normal HTTP client derives three things from the verb without being told: whether a call is safe to repeat, whether a response can be cached and whether a failed request can be retried blindly.
On an interface where reading and deleting are both POST, none of those inferences hold, and every one of them has to be decided per path instead.
Twelve of the 48 paths carry a get segment, and every one of them is reached with a POST.
Two paths delete. Both are POST, and both mark rather than remove.
Four paths update, all POST, and the parties sit behind settings.
The method stops being a signal. Safety, caching and retry behaviour cannot be read off the verb here, so they have to be decided per path instead of per request.
The operations are not spread evenly either, and the distribution says what the product is for. Two tags carry eleven operations each, and one of them is not an accounting object at all but the settings surface where the parties live.
| Tag | Ops | What it covers |
|---|---|---|
| Postings | 11 | Add, batch, unconfirm |
| Settings | 11 | Debtors, creditors, accounts |
| Receipts | 8 | Upload, assign, delete, restore |
| Transactions | 8 | Read and match to receipts |
| Cost locations | 4 | The only full round trip |
| Invoices | 3 | Create, draft, e-invoice |
| Accounts | 2 | Read and add |
| Comments | 1 | Add |
Tags and counts taken from the operation list in the vendor reference, checked 19 August 2026. Cost locations is the only tag carrying add, get, update and delete together.
Four limits, and the tightest sit on the write paths
This is the part that decides your architecture, and it is the part that neither our own system page nor the article it replaces mentions. The reference publishes a ceiling in one sentence: “It is only allowed to make a maximum of 100 requests per customer per minute to the API.” Per customer, not per application, which is the good news: your hundredth customer account does not slow down your first.
The other three are easier to miss because they are not in the limits section at all. They sit as implementation notes on individual operations, and counted across the reference there are exactly three of the 48: /receipts/upload carries “Note: max 10 requests per minute”, while /receipts/addBatch and /transactions/addBatch each carry “Note: a request is allowed only every 5 seconds”.
Put those facts next to what this product does and the shape of the constraint appears. BuchhaltungsButler exists to take receipts in and turn them into bookings, and every operation that writes at volume is capped below the global ceiling: the single upload at a tenth of it, and the two batch paths at twelve requests a minute each. The 100 per minute is the budget for reading, writing has its own and much lower one.
A migration of a customer’s back catalogue is therefore not bounded by your worker count or their plan. It is bounded by ten uploads a minute, or by one batch every five seconds if you go that way, and no amount of parallelism moves either number.
- Every operation, per customer
- 100 / minute
- The ceiling the reference states for the interface as a whole.
- Receipt upload, per minute
- 10 / minute
- Its own note on /receipts/upload.
- Receipts, batch endpoint
- 1 / 5 seconds
- Its own note on /receipts/addBatch.
- Transactions, batch endpoint
- 1 / 5 seconds
- Its own note on /transactions/addBatch.
The poll comes out of the same allowance. No object here announces its own changes, so every check for what moved is a request you spend, and the three write endpoints each have their own floor to stay under while you spend it.
Global ceiling from the API limits section of the vendor reference; the three endpoint notes from the implementation notes of those operations, checked 19 August 2026. The reference does not document a status code for exceeding any of them, so read the response and do not assume it.
Customers and suppliers are debtors and creditors in settings
There is no contact object here, and there is no customer object either. The parties exist as debtors and creditors, and they are not filed with the documents that reference them. All eight operations that read, create and update a party sit behind a settings path.
That is a bookkeeping view rather than a product view, and it is internally consistent: in a system whose job is classifying documents, a debtor is a piece of configuration that decides where a receipt lands. It is simply not the view your product has, where a customer is a first-class thing with a name and an address.
It is also the clearest case on this system for reading through a normalised layer. The common data model gives you customers and suppliers as objects with the same fields you use on every other connected system, and the fact that one vendor keeps them under settings and another under contacts stops being something your code knows about.
POST /api/v1/settings/add/debtorPOST /api/v1/settings/add/creditorPOST /api/v1/settings/add-batch/debtorsPOST /api/v1/settings/update/debtor
Four of the eight party operations. The other four read them back and update creditors, and every one of them keeps the settings prefix.
Paths from the Settings tag of the vendor reference, checked 19 August 2026. Through Maesn the same records read as customers and suppliers, which are the two objects here that make the full round trip of read, create and update.
A deleted receipt is a flag, and a fixed posting stays put
Two behaviours here will surprise anyone who assumes a document store. Neither is mysterious once you read the operation notes, and both change what your code has to tolerate.
The first is that deletion does not delete. The reference describes the operation as “Mark a receipt as deleted for a specified customer account”, and there is a matching operation to “Restore a marked as deleted receipt”. A removed document is a state, and anything you write that reads without accounting for that state will keep seeing it.
The second is that bookings can become immovable. All three unconfirm operations, for free postings, receipt postings and transaction postings, carry the same sentence: “This will only work if the postings are not fixed.” Once a posting is fixed, the path back is a new posting rather than an undo, which is ordinary accounting behaviour and unusual API behaviour.
There is a third habit worth planning for, because it costs a request. Six operations identify their target by id_by_customer, and the reference tells you where to get it: “You can get the ‘id_by_customer’ by using the ‘/receipts/get method’ first.” A delete is therefore two calls, and both of them come out of the same hundred.
POST /api/v1/receipts/get-> id_by_customerPOST /api/v1/receipts/delete/id_by_customer-> marked as deleted, restorable
Two requests against the per-customer allowance for one logical operation, and the second one is reversible by design.
Quotations from the implementation notes of the receipt and posting operations in the vendor reference, checked 19 August 2026. The reference does not define when a posting becomes fixed, so handle the condition instead of predicting it.
One scheduled read, and it shares your request budget
BuchhaltungsButler does not announce its own changes, so there is no subscription to configure and no callback to verify. Staying current is a scheduled read. That is a property of the system and not a setting, so it belongs in the plan from the start.
What takes its place is a delta pull on the same filters and the same paging you use everywhere else: you ask what changed since your last run and you get it back in the shared model. In the event model that is the pull half doing the work, and on this system the push half has nothing to fill it.
A pull has one property a push does not, and on this system it is the relevant one. It catches up. If your worker is down for an hour, the next run still returns everything that moved in that hour, and on a platform where documents arrive in batches from a scanning app that matters more than latency does.
What it costs is requests, and requests are the thing that is capped. Every poll is spent from the same hundred per customer per minute as your writes, so the interval is a budget decision rather than a preference. Reading rarely and asking for a wide window is cheaper than reading often and asking for a narrow one.
What Maesn covers, and what stays with you
The connection here is short work, which is exactly why the rest deserves attention. What we take off the list:
- The verb translation. Your client uses the ordinary REST verbs and the mapping onto 48 POST paths lives on our side, so the two inferences an HTTP client normally makes stay available to you.
- The two credential layers. The Basic Auth pair and the per-customer key are stored with the connection, so the account selector stops being something your request builder can get wrong. How the party model maps is on the BuchhaltungsButler API page.
- The party model. Debtors and creditors under settings arrive as customers and suppliers, with the fields they have on every other system.
What stays with you, and the first of these is a decision rather than a task:
- How you spend the hundred. We do not turn this into an event source, because it is not one. How fresh your product needs to be, and what that costs against a per-customer ceiling, is a product decision we can inform and not replace.
- The pace of a backfill. Ten uploads a minute is the vendor’s number, and no interface in front of it makes the eleventh upload succeed.
- The net amount, if you need one. This is one of three connected systems that carry a single gross amount field, with net and tax empty. Deriving a net basis is arithmetic on your side or a question for a different source.
- The click in your customer’s account. Activating access and copying three values is theirs to do, and saying so clearly in your own interface is the difference between a connection and a support ticket.
Frequently asked questions
What are the BuchhaltungsButler rate limits?
Why does a read request have to be a POST?
What is the difference between the API Client, the API Secret and the API Key?
Does deleting a receipt actually remove it?
Why can I not unconfirm a posting?
Where do customers and suppliers live in BuchhaltungsButler?
Can I get a net amount from a BuchhaltungsButler invoice?

QuickBooks Online Webhooks: Events, Retries and Recovery
QuickBooks Online webhooks cover 29 entity types and expect HTTP 200 in three seconds. Why Intuit still asks you to poll change data capture.
Lennart Svensson · 25 Aug 2026
Lexware Office Pagination: The 406 and One Page Size
Lexware Office validates the page size and rejects a bad one with 406, the same code it uses for an unsupported media type. What that means for your read loop.
Lennart Svensson · 20 Aug 2026
How to Integrate with DATEV Rechnungswesen: One Connection
One connection carries reading and writing in DATEV Rechnungswesen, on a two-year token. Which objects travel in which direction is the real decision.
Lennart Svensson · 17 Aug 2026Build once on the Unified API.
BuchhaltungsButler meters ten uploads a minute, sevdesk publishes no limit at all and Xero meters what you read. Build against one interface and each of those becomes a row in a table rather than a project.