How to integrate with Lexware Office: Two requests per second and no polling
Lexware Office is not a hard system to call. It is a hard system to call often. Three documented rules decide your architecture before you write a line: the rate limit covers every endpoint at once, every write needs a read first and Lexware asks you not to poll.


Why Lexware Office decides German SMB coverage
Lexware Office is where a large share of German small businesses, freelancers and their tax advisors keep their books. If your product sells into that market, covering it is often the difference between shipping in Germany and explaining why you cannot.
What makes it demanding is not the protocol. It is a REST API, and reaching a single record is unremarkable. The difficulty is that German accounting law sits inside the data model, and that the platform protects itself with rules that shape your architecture rather than your request bodies.
This guide is about those rules. If you want the data model, the authentication options and the marketplace levels in one place, that is the Lexware Office API page. What follows is how to build against the platform without running into the three constraints that catch most first implementations.
Who can connect and on which plan
Two things decide whether your customer can connect at all, and both sit outside your code: the plan they are on, and your own relationship with Lexware.
The route open to everyone is the public API, authenticated with an API key. Lexware states that it is available from version XL upward, so a customer on a smaller plan has no key to give you.
The key is created inside Lexware Office by a user with administrator rights, on the public API add-ons page. It belongs to that one account, so each of your customers goes through it once for their own environment.
There is a second route, and it opens through a partnership with Lexware. That is a manual qualification with their partner team. It reaches a wider set of endpoints and operations, it authenticates differently, and it runs under a higher rate limit.
Maesn supports both routes, the endpoints as well as the authentication, so your implementation does not change with the one your customer ends up on. We run the qualification with you rather than handing you a form.
Lexware publishes the programme itself, including the benefits that come with it beyond API access. In practice the two that matter commercially are co-marketing and a listing in the Lexware marketplace. Maesn has been through it: Lexware lists us as a partner on their own site, which is the only kind of proof for a claim like that which does not come from us.
Plan requirement and programme from Lexware’s own public API partner page, checked 4 August 2026.
The plan check belongs in your connect flow, not in your support inbox. A customer who cannot produce a key will read a failed connection as your bug. Say which plan is needed before they try, and say what the alternative route is.
Two requests per second, across every endpoint
A client may send two requests per second. The important half of that sentence is the scope: Lexware documents that the limit refers to all endpoints at the same time. It is one budget for your whole integration, not one per resource.
That budget belongs to the public route. Going through a partnership raises it, which is worth knowing if volume is the reason you are reading this section at all.
The mechanism is a token bucket, and exceeding it returns 429 without performing the call. Lexware recommends running a token bucket on your side too, or at minimum a sleep between consecutive calls with exponential backoff on 429. They also warn that network jitter alone will trip a client that enforces the limit exactly, so plan below it rather than at it.
The authorization server has its own limits, and those are not published. The consequence there is harsher than a rejected call: a client that keeps sending gets blocked for seconds to minutes, and one that does not slow down stays blocked until it does.
Retry behaviour, backoff and the difference between a rejected call and a blocked client are the same problem on every system we support, which is why it sits in unified error handling rather than in each integration.
read the current version
send it back with that version
One update fills the second. Every other call, including the next update, waits for the next one.
| Layer | Limit | On exceeding |
|---|---|---|
| Resource endpoints | 2 requests per second, all endpoints together | 429, the call is not performed |
| Authorization server | separate, not publicly documented | 429 plus a temporary block that becomes permanent while the rate stays high |
Both rows from Lexware’s API documentation, section API Rate Limits, checked 4 August 2026.
Every update starts with a read
Lexware uses optimistic locking, so a record is never locked before you modify it. Instead every PUT has to carry the version you received from your last GET of that record. If something else changed it in between, your version is stale and the write is refused.
version is read-only and increases on every change. You cannot compute it, and you cannot cache it for long, which is the part that costs you.
GET /v1/contacts/{id}→ 200 { "id": "f5d5e4c2…", "version": 2, … }PUT /v1/contacts/{id}{ "version": 2, … }→ 200 { "id": "f5d5e4c2…", "version": 3, … }PUT /v1/contacts/{id}{ "version": 2, … } # someone else already wrote version 3→ 409 Conflict
Field semantics from Lexware’s documentation, section Optimistic Locking. Endpoint paths shortened for readability.
One update is two calls, and your budget is two calls per second for everything. So a naive loop over records manages roughly one update per second and leaves nothing for reads, webhooks or anything else your integration is doing at the same time.
That is not a benchmark we ran, it is the two documented rules above put next to each other. It is also why bulk work against Lexware belongs in a queue with a rate governor, not in a request handler.
Polling is not allowed, so the sync runs on events
Lexware is explicit about this. Their cookbook says polling resources is to be avoided and names webhooks as the way to keep two systems in step. Combined with the budget above, that is less a recommendation than a design constraint: there is no rate at which polling both stays inside the limit and keeps data fresh.
Natively, Lexware sends an event such as invoice.status.changed to a callback URL you registered, with the account, the resource id and the time of the change. Delivery failures are retried over 48 hours, and their own guidance is to accept the call into a queue and process it asynchronously rather than doing the work in the handler.
Through Maesn you subscribe per customer to a resource and an event type, and you receive the same shape you receive for every other system. That is what unified webhooks means in practice: one payload, one subscription call, whatever the platform underneath emits.
await axios.post(url, {callbackUrl,eventType: "CREATED",resource: "CUSTOMER"}, { headers: { "X-API-KEY": apiKey, "X-ACCOUNT-KEY": accountKey } });// what arrives at callbackUrl{"eventType": "CREATED","filterDate": null, // not supported by Lexware"resource": "CUSTOMER","resourceId": "1605408d-ed88-4228-8a12-ab857a2972d8","userId": null // not supported by Lexware}
Request and payload shape verbatim from the Maesn Lexware Office documentation.
- eventType
- invoice.status.changed
- organizationId
- aa93e8a8…
- resourceId
- 4d43ad14…
- eventDate
- 2023-05-23T12:30:00.000+02:00
- resource
- INVOICE
- eventType
- UPDATED
- resourceId
- 1605408d…
- filterDate
- nullnot sent by Lexware
- userId
- nullnot sent by Lexware
Two things stay yours. The subscription is created per customer, so a new connected account means a new subscription, and filterDate and userId arrive empty for Lexware. Unifying a payload does not invent data the source never sent, and an integration that branches on those two fields will branch wrongly here.
Keys expire after 24 months, and revocation arrives as an event
An API key is not permanent. Lexware sets its lifetime to 24 months and renews it in the same key management screen where it was created. A connection that has worked for two years is therefore a connection that is about to stop working.
A customer can also end it earlier, and there is a signal for that. Maesn emits a TOKEN resource with the event type REVOKED when a customer withdraws access or the token can no longer be refreshed. Handling it is the difference between telling the customer their connection is gone and finding out from their support ticket.
One more thing worth building for: a customer may create several keys and may restrict what a key is allowed to reach. If they restrict it below what you need, your calls fail with 403 and not 401. The credential is valid, the permission is not, so tell them which scope you need at the moment they create the key. How that folds into one flow across systems is unified authentication.
Key lifetime and multiple keys from Lexware’s public API cookbook, checked 4 August 2026. The 403 semantics are from their HTTP status code table, the TOKEN event from the Maesn documentation.
What German law puts in your data model
Some fields are not optional, and they are mandatory for legal reasons rather than technical ones. Three of them will reach your own model whether you planned for them or not.
| Field | What it is | The catch |
|---|---|---|
| currency | Currency of a price and of a line total | Documented as EUR only. Convert on your side and keep the original amount and rate |
| xRechnung.buyerReference | The Leitweg-ID for invoices to German public sector buyers | If it is set, vendorNumberAtCustomer has to be set as well |
| electronicDocumentProfile | NONE, EN16931 (ZUGFeRD) or XRechnung | Read-only, so it tells you what a document is and not what you want it to be |
All three from Lexware’s API documentation, contact and line item properties, checked 4 August 2026.
There is a second layer to what a given customer can actually do, and it is easy to get wrong: the features their Lexware contract grants are documented as orthogonal to the permissions on the key, and they change over time. Lexware therefore exposes the available set on the profile endpoint. Read it instead of assuming it.
What stays on your side: Taxes, currency and the plan
We absorb the shape of the integration, not the rules of the platform. Five things stay with you, and it is cheaper to know that now than after the first customer call.
- Tax is not calculated by Maesn. We deliver the rates and structures as the system publishes them. What you owe, and on which basis, stays your model.
- Currency conversion is yours. Lexware supports EUR only, so the converted value and the rate you used are decisions on your side.
- The plan requirement is Lexware’s. We can tell you it exists and where it applies. We cannot lift it for a customer who is not on it.
- The partner qualification is Lexware’s decision. We prepare it and walk through it with you, and we do not grant it.
- Per-customer subscriptions stay per customer. One connected account, one subscription. That is the platform’s model and not something to abstract away.
Attachments are the clearest place to see where that line runs, so here is the whole thing: putting a document on a booking is four steps on this platform. Create the transaction, update the balance on the finance account it belongs to, upload the file, then link the file to the transaction. It is more than four calls, because the balance update is a read and a write for the reasons above. Against our own endpoint it is one request: POST /accounting/transactions, the transaction as JSON and up to six files in the same multipart body. You never see the file endpoint, the voucher id it returns or the call that links them.
Three limits come with that, and they are yours to design around.
- It ends at a suggestion. The call that ties a file to a transaction is named a hint, and that is exactly what it does. The document arrives in the Lexware web UI as suggested, and a person confirms it. Lexware exposes nothing stronger, so nobody can automate that last step, us included.
- It needs an external reference from you. The link is made on a reference you send with the transaction, not on an id you get back. No reference, no link.
- It is best effort, not atomic. A chain of calls has no shared transaction and no rollback. If the upload fails after the booking is written, the booking stays written, and your retry has to expect that.
One more thing to plan for, because it is in neither documentation. Step one needs the id of the finance account, and there is no endpoint that lists them. You can fetch one by id and that is all, so the id comes from creating the account or from a person reading it out of the Lexware UI. Watch the naming while you look for it: our accounts endpoint returns booking categories, which are a different thing entirely.
The four steps, the single request and the three limits were verified against our own implementation on 11 August 2026. Lexware documents the file endpoint but not this chain, so read this section as our first-hand account rather than as a quote from their reference.
Lexware does not allow load or performance testing against the public API, and they run no acceptance check either. Nobody signs off your integration, and nobody wants you hammering production to find out where it bends.
Frequently asked questions
Is there a Lexware Office sandbox?
What are the Lexware Office rate limits?
Why does my update return 409 Conflict?
Does Lexware Office support webhooks?
Which plans can use the Lexware Office public API?
Which currencies does Lexware Office support?

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.
Rate governors, version reads, per-customer subscriptions and key renewals are the same problem on every accounting system. Solve them once with Maesn instead of once per platform.