maesn
Product insight

Asynchronous processing takes the whole batch, at every system's pace

Maesn adds no rate limit of its own. The systems behind it do, in units that have nothing in common, so the queue absorbs your volume and releases it at a pace each target allows, one tenant's requests in sequence, with long operations answering immediately with a task you can follow.

One burst from your appall at once
maesn paces each stream
Each system, at its own limit
Sage Active3.000 / min
Lexware Office2 / sec
AbaConnect1 at a time
Trusted by winning software teams
HubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinHEROHolviLanes & PlanesAgicapHubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinHEROHolviLanes & PlanesAgicap
The concept

What is asynchronous processing

Sending a thousand invoices is not a throughput problem. Your side can produce them in a second, and the network will carry them. The question is whether the system at the other end will accept them at that speed, and the answer is almost always no, in a way that is specific to that system and written down somewhere you have not read yet. Volume in an integration is a question of permission, not of performance.

Asynchronous processing is the layer that answers it for you, and the mechanism is a queue. Instead of passing your request straight to the target system, Maesn enqueues it and works that queue at a pace the target accepts. If a system takes five requests a second, you can hand over a hundred: they leave the queue five at a time, in the order you sent them, and none of them comes back asking you to slow down.

Three things follow from the queue rather than one. The pace is the first. The second is that some operations cannot be finished while a connection is open, so they answer with an identifier for the work instead of the result, and you follow it up when it suits you. The third is the one that costs the most when it goes wrong: requests leaving a queue one at a time cannot collide over a token refresh, which is a failure that ends with your customer logging in again. All three remove the same assumption from your code, that a request is finished the moment you send it.

A layer in the middle is where you would reasonably expect to meet another limit. The rate limiting reference puts it in one sentence: Maesn's unified APIs do not implement any specific rate limits. The limits that matter belong to the target systems, they apply to Maesn's tenants, and the work is in absorbing them rather than passing them on.

The problem

Every system counts something different

A rate limit is never just a number. It is a number, a window, and the thing the window applies to, and no two systems agree on all three.

System
AbaConnectOne active request at a timeconcurrency
Lexware OfficeTwo requests per second, over a token bucketper second
abacus200 per minute, 12.000 per hour, 30.000 per daythree windows
Exact Online60 per minute and 5.000 per day, per companyper company
Business Central5 concurrent, 6.000 per five-minute windowper user
QuickBooks500 per minute, 10 concurrent, per realm IDper realm
Twinfield1.000 credits per minute, a GET costs 1, a POST costs 3API credits
Xero5 concurrent, 60 per minute, 5.000 per dayper tenant
DATEV RechnungswesenA limit is enforced, the value is not publishedunpublished
bexio, sevdesk, weclappA limit is enforced, the value is not publishedunpublished

Read that list as a specification and the size of the job becomes obvious. A limiter that respects two requests per second is the wrong shape for one that counts two hundred a minute against three windows at once, and both are the wrong shape for a system that accepts one request at a time, or one that charges a GET and a POST different amounts from a shared budget. Whether the budget belongs to your application, the end customer's company, a user or a tenant decides whether one customer's busy afternoon can starve another's. And where the value is not published, the only way to find it is to exceed it in production.

One lever comes before pacing and is the cheaper of the two: the request you never send costs nothing. Asking each system only for what changed since your last sync, through the delta filter on almost every endpoint, keeps most sync jobs comfortably under limits that a full re-read would breach every night. Pacing is what carries the volume you genuinely have to send.

How Maesn handles it

One burst in, a pace each system accepts

Fire hundreds or thousands of requests at Maesn and they are accepted, held and released to the target system at a rate it allows. Nothing in your code changes between a system that permits two calls a second and one that spends a thousand credits a minute where a GET costs one and a POST costs three, and nothing in your code has to know which is which. A weekly batch of tens of thousands of invoices is the ordinary case, not the edge case. The work arrives, without you managing when.

Order matters more than rate, and this is the part tenants ask about most. Requests for one tenant leave the queue one after another rather than in parallel, and a queue of one cannot race itself. Fired in parallel instead, two requests can both discover that the access token has expired, and the second starts a refresh while the first one is still running. On some systems that ends the session. On DATEV it is worse: the tokens are invalidated, so the customer has to walk back through authentication for a connection that was supposed to be authorised once and then run for years. The cause is a burst sent slightly too fast, and the effect lands on the person least able to understand it. Sequencing removes the race rather than retrying after it, and for many DATEV integrations that, rather than the pace, is the reason the queue is used at all.

What you send
1.000 invoices to createone loop
No delay between the callsno limiter
No 429 bookkeepingno counters

Requests for one customer are released one after another, so a token refresh cannot land in the middle of a burst.

maesn absorbs and paces
What the system receives
rate <= the target's own limit

A steady stream at a pace that system allows, in the order you sent it, instead of a spike it answers with 429.

Two layers are at work here and they have to be kept apart. On Maesn's side: no limit of its own on the way in, pacing out to each target, sequencing per tenant. On your side: a target system can still answer 429, for reasons outside this stream, and when it does you get a standardised error type for exactly that case plus documented retry guidance, an initial delay of one minute that doubles with each attempt. What Maesn absorbs is the part you would otherwise model. What reaches you is the part that genuinely needs a decision.

Asynchronous tasks

Some work does not finish in one request

Uploading a document, posting a booking proposal or writing a batch of journal entries can take longer than a request should stay open. Those operations answer with a task instead of a result.

One task to follow

An asynchronous operation answers immediately with a taskId instead of holding the connection open until the system is done.

Partial data straight away

Where the operation supports it, the first response already carries the object you sent, with the taskId alongside it.

A status you can act on

Tracking the task returns its status, and once the system has finished, the created object under responseData.

What happened, not just that it ended

An information array carries the messages the system reported, each with a filename, a timestamp and a type.

asyncTask.json
"data": {
"status": "SUCCESS",
"information": [
{
"filename": "Invoice_V30",
"message": "The document has
been received.",
"type": "information"
}
],
"responseData": { … }
}

The mechanics are the same wherever it applies. The response body carries a taskId, you pass it to GET /asyncTask, and you get back the status of the work plus the object the system created once it is done. The endpoints below are the ones that behave this way today.

Which operations those are is not entirely Maesn's choice. A synchronous request can always be made asynchronous; the reverse cannot be done at all, so where a target system answers asynchronously the Unified API mirrors it instead of pretending to hold the line open. That is usually a write, because entering data is the slow half and the half that arrives in bulk, while a read can normally be finished in one go. AbaConnect is the exception worth knowing about: asking it for a contact returns an identifier rather than the contact, and the record is collected on a later call once the system reports itself finished.

Endpoints that can run asynchronously
Booking proposals
POST /bookingProposalsPOST /bookingProposals/async
Contacts
GET /contactsPOST /contactsPOST /contacts/bulk
Expenses
POST /expensesPOST /expenses/async
Files
POST /files/async
Journal entries
GET /journalEntriesPOST /journalEntries/bulk
Projects
GET /projectsPOST /projects
Sales orders
POST /salesOrders
Transactions
POST /transactions

Polling a task is the simple option and often the right one inside a job you already run on a schedule. It is not the only one. Where a target system processes a write asynchronously on its own side, the kind of system where you would normally post, wait and poll for the outcome, Maesn can tell you the result as a webhook event, success or failure, so the waiting leaves your code entirely.

Why it matters

Volume stops being yours to model

Building it yourself
  • Model a limiter per system, per unit
  • Track windows, credits and concurrency
  • Serialize calls around token refreshes
  • Hold connections open for slow writes
With Maesn
  • Send the burst, Maesn paces it out
  • The limits are published, not guessed
  • Requests sequenced per customer
  • Long operations answer with a taskId

Rate limits are the part of an integration that works in testing and fails at scale. Ten invoices behave; the month-end run of ten thousand does not, and by then the fix is a queue, a limiter and a retry policy per system, written by whoever is on call. Every new system your customers ask for adds another set of numbers and another unit to that machinery, none of it the product you set out to build.

Because the pacing, the sequencing and the task tracking belong to Maesn, that machinery does not accumulate on your side. You send what you have when you have it. The system your customer picks next changes the pace on the wire, not the code that produced the requests. That is the part product and engineering teams never have to build twice.

Asynchronous Processing FAQ

Common questions

Does Maesn rate limit my requests?

No. The rate limiting reference states plainly that Maesn's unified APIs do not implement any specific rate limits. What does apply are the limits of the systems behind the API, and those apply to Maesn's tenants, which is why the queue paces traffic out to each target rather than Maesn adding a limit of its own on the way in.

What happens if I send more requests than a target system allows?

It depends on whether they go through the queue. Sent through it, they are absorbed and released to the target at a pace that system accepts, so they arrive without you spacing them out yourself. Sent straight through on a synchronous call, the target's own answer reaches you: a 429 surfaces as its own standardised error type rather than a generic failure, and the documented retry is an initial one-minute delay that doubles with each further attempt. The backoff on that path is yours.

How different are the limits between systems?

Different enough that a limiter written for one system is useless for the next. Lexware Office allows two requests per second over a token bucket, abacus 200 per minute alongside 12.000 per hour and 30.000 per day, AbaConnect a single active request at a time, and Twinfield counts API credits where a GET costs one and a POST costs three. Others count per company, per user, per realm or per tenant, and bexio, DATEV Rechnungswesen, sevdesk and weclapp enforce a limit without publishing the value.

What is an asynchronous task?

A request for an operation that cannot be completed while you wait. Instead of holding the connection, the response body contains a taskId, a unique identifier for the work that is now running. You pass it to GET /asyncTask to check progress or fetch the result, so nothing in your application has to sit and block on a slow target system.

Which endpoints support asynchronous operations?

Booking proposals, expenses and files each have an async endpoint, contacts and journal entries have bulk endpoints, and contacts, journal entries, projects, sales orders and transactions run asynchronously on their regular endpoints. All of them return a taskId in the response body, and all of them are tracked the same way.

Do I have to poll for the result?

You can, by calling GET /asyncTask with the taskId, which returns the status plus the created object under responseData once the system is done. For systems where a write is processed asynchronously on their side, Maesn can also notify you by webhook when the response is ready, whether it succeeded or failed, so the waiting does not have to happen in your code at all.

Why can sending requests in parallel break authentication?

Because of a race condition around token refreshes. Two requests sent at once can both find the access token expired, and the second begins a refresh while the first one is still running. Some systems end the session; DATEV invalidates the tokens, so the end customer has to authenticate again for a connection that was meant to be authorised once and then left alone. Requests that go through the queue leave it one at a time, so your side can still fire them in parallel while they reach the target in sequence and never overlap on a refresh.

Does pacing make my integration slower?

It spreads a burst over the time the target system needs to accept it, which is the same time the target would have taken anyway. The alternative is not a faster integration but a partly failed one, with some requests rejected and a retry queue of your own to run. What changes is where the waiting happens: inside Maesn rather than inside your application logic.

Where do I look up the limit for one specific system?

In the rate limiting reference, which lists every connected system with its current limit and cites the provider documentation the value comes from. Where a provider enforces a limit without publishing the number, that is documented as such rather than filled in with an estimate.

Build once on the Unified API.

See how asynchronous processing works for your integration, or dive into the technical reference.