Handle every customisation outside the model, still inside your integration
Real installations carry things a shared schema cannot. Raw Data returns the untouched payload next to the normalised one, Authenticated Passthrough calls any native endpoint directly, and both keep the base URL, the credentials and the tenant identifiers on Maesn's side.
GET /contacts?rawData=true POST /accounting/passThrough
What is customisation handling
A common data model is an intersection. It carries what systems genuinely share, which is what makes one invoice object work across all of them, and it therefore cannot carry what only one customer's installation has. That is not a gap in the model, it is the definition of one. Every serious integration meets the moment anyway: a field somebody added years ago that a report depends on, an object type the vendor never standardised, a native call that does something no unified endpoint offers.
Customisation handling is the answer to that moment, and there are exactly two documented mechanisms. Raw Data is for reading more than the model returns, described in the docs as access to data that is not covered by the unified responses. Authenticated Passthrough is for making calls the unified API does not make, described as calling system endpoints even if they have not been explicitly implemented. One widens the response, the other widens the surface.
Both are escape hatches, and an escape hatch is judged by what it makes you rebuild. These two remove the normalisation and nothing else: the authentication, the base URL and the identifiers that say which tenant you mean all stay where they were. Going off the common data model for one field therefore does not mean going off Maesn, and the model stays the default path for everything else in the same codebase.
The usual escape hatch drops you back to zero
Most integration layers offer a way around themselves. The question is the price, because the moment you leave the unified endpoint, four things are usually yours again.
None of those four is hard on its own. Together they are a second integration living next to the first, and it is the one nobody documents. The base URL differs per system and sometimes per installation, which means it cannot be a constant. The tenant identifier has a different name and a different source in every system: a realm ID on QuickBooks, an environment name on Business Central. And the protocol is not even always REST: some systems answer GraphQL, others still speak SOAP, and both need shapes a REST client does not produce.
The credentials are the item that reads smallest and costs most. They belong to the customer, and the access and refresh tokens behind a Maesn connection are not yours to read, so a call you make on your own needs an authorisation of its own. The same customer clicks connect a second time, signs in to a system they already connected, and from then on maintains two connections to it, one of which exists because of a single endpoint. Storing those tokens and refreshing them is then also yours, and that is the half of this cost that usually gets mentioned.
So the useful question is not whether a way around the abstraction exists. It is which parts of it you keep when you use one, and which single part you knowingly give up.
The full payload, next to the normalised one
One query parameter on a GET request. The unified object still arrives, and the record as the system returned it arrives beside it.
The normalised object, the same on every system.
The record as the system returned it, untouched.
Setting rawData=true does not switch the response into a different mode, it adds to it. Your existing code keeps reading data exactly as before, and the one field you were missing is in rawData next to it. That is the difference between an escape hatch and a fork: nothing has to be rewritten to look at what the system actually said.
That also makes it a debugging tool, which is the use nobody plans for and everybody ends up needing. When a value looks wrong in your product, having both halves of the same response side by side tells you immediately whether the source system sent it that way or whether it changed on the way through. Without that, the same question turns into a support ticket and a guess.
It is available on all GET endpoints and for all target systems, which also means it composes with everything else those endpoints do. Because it is the same request, the same filtering, ordering and paging still apply, so you can ask for the last day of changes and get the untouched payload for exactly those records.
One endpoint, whatever the system speaks
Passthrough is one POST /accounting/passThrough carrying three things: the relative path, the method and, for writes, the body. All five methods are supported, so a native read, create, update or delete is the same call with a different verb. There is no separate credential, no separate host and no second client to configure.
The part worth looking at is what happens for systems that do not speak REST. A GraphQL system takes no path at all and your query travels in the body. A SOAP system takes no path either and you send the body contents base64 encoded, which Maesn then wraps in the envelope that system expects. Three transport worlds, one request from where you sit.
For SOAP you send only the contents of the body element; the envelope, the access token and the company code are added around it.
One endpoint, two headers and a relative path. The transport differences stay on Maesn's side of the call.
The word doing the work in the feature name is authenticated. The customer connected their system once through unified authentication, and that connection is what carries a native call too. You send your two Maesn headers; the target system's own token, the access token inside a SOAP envelope and the identifiers that tell it which tenant you mean are added on this side of the call.
That is the part a call built outside cannot borrow. The tokens are not yours to read, so your own endpoint needs its own authorisation, and the customer signs in a second time to reach a system they have already connected. Passthrough is the escape hatch that never asks for it: one consent, one connection, and the native call travels on that.
You give up the shape, not the connection
A native response arrives in the system's own form, with its own field names, and the mapping for it is yours. Everything underneath the shape stays where it was.
Being precise about this is more useful than promising that customisation is free. What you give up when you leave the unified endpoint is normalisation: one response shape, one set of field names, one way to read every system. What you keep is everything in the table above, which is the part that takes the longest to build and never stops needing maintenance.
Two things do not change either. A native call travels on the customer's own connection, so it can do what that connection can do and no more. And the target system's own rate limit still applies to that traffic, the same published limits that asynchronous processing lists per system, so a batch of native calls spends the same budget as any other request.
The edge case stops being a second project
- A second integration for the edge cases
- Base URLs and tokens per system again
- Tenant identifiers threaded by hand
- SOAP and GraphQL handled separately
- One switch for the full payload
- One endpoint for any native call
- Authentication stays Maesn's job
- Every protocol behind one request
Integration projects are rarely lost on the standard case. They are lost on the one customer whose setup is not standard, because that is where a clean abstraction usually turns into a direct integration built beside it, with its own credentials, its own host and its own bugs. Before long there are two integrations to maintain for every system, and only one of them is documented.
With one query parameter for the full payload and one endpoint for any native call, the exception stays inside the same integration. Your customer gets the field they asked about, and you do not sign up for a parallel code path to deliver it.
There is a second effect that shows up in your own backlog. Without a way to reach past the model, every unusual requirement arrives as a request to you: add this field, expose that object, support this one system differently. Those requests accumulate faster than they can be built, and each one competes with the roadmap. When customers can reach the data themselves, the request stops being yours to schedule, which is worth more than the feature it replaces. A roadmap that stops absorbing one-off field requests is the clearest thing product and engineering teams get back here.
Common questions
What is Authenticated Passthrough?
What is Raw Data?
Do I have to choose between the two?
Can we use Raw Data to debug a wrong value?
How does this help us as a software vendor, not just our customers?
Which HTTP methods does passthrough support?
Do I need the full URL of the target system?
What about systems that are not REST?
Is the passthrough response normalised?
Are there system specific quirks I should know about?
Do the target system's rate limits still apply?
Build once on the Unified API.
See how customisation handling works for your integration, or dive into the technical reference.











