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.
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.
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.
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.
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.
Requests for one customer are released one after another, so a token refresh cannot land in the middle of a burst.
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.
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.
"data": {"status": "SUCCESS","information": [{"filename": "Invoice_V30","message": "The document hasbeen 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.
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.
Volume stops being yours to model
- Model a limiter per system, per unit
- Track windows, credits and concurrency
- Serialize calls around token refreshes
- Hold connections open for slow writes
- 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.
Common questions
Does Maesn rate limit my requests?
What happens if I send more requests than a target system allows?
How different are the limits between systems?
What is an asynchronous task?
Which endpoints support asynchronous operations?
Do I have to poll for the result?
Why can sending requests in parallel break authentication?
Does pacing make my integration slower?
Where do I look up the limit for one specific system?
Build once on the Unified API.
See how asynchronous processing works for your integration, or dive into the technical reference.











