maesn
Product insight

Unified logging and monitoring across every system, not one log per vendor

Every API call is logged in the same structured form: the endpoint, the response, the timestamp, the target system and the account key. The systems all answer differently, the record does not, and it shows that a transfer happened rather than storing what moved.

Three calls, three systemsone record
POST /invoiceslexware-office
GET /contactsdatev
POST /expensesxero
maesn logs each one the same way
Always these five things
endpointPOST /invoices
response201
timestamp
targetSystemlexware-office
accountKey<account-key>
Trusted by winning software teams
HubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinHEROHolviLanes & PlanesAgicapHubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinHEROHolviLanes & PlanesAgicap
The concept

What is unified logging and monitoring

With one integration, debugging is a matter of reading two records: yours and the system's. The cost of adding the next system is not linear, because the question changes. It stops being what went wrong in our code and becomes where this went wrong, and every system answers that question in its own format, through its own portal or through none at all, on its own clock.

Unified logging and monitoring is what keeps that question answerable from one place. Every API call is logged in the same structured form, holding the endpoint that was called, the response, the timestamp, the target system and the account key. That is enough to reconstruct what happened at what time, for one tenant, across systems, without opening anything else.

Records are kept for 30 days on Start and Scale and 90 days or more on Enterprise, so how far back you can investigate is part of the plan you are on.

The word doing the work is unified. The systems' own responses and messages have nothing in common, and normalising them is what makes a single record shape possible at all, whether you read it in the Maesn portal or through the API. It is the same normalisation principle as the error envelope you already handle, applied to the trail a call leaves behind instead of to the answer it returns.

The problem

The question is rarely what broke, it is where

Four places to look when a sync fails, and each of them can only see part of it.

Your own logs
your side onlyno system detail
The system's portal
one systemif it has one
The customer
a screenshothours later
Across all of them
no shared idno shared clock

Your own logs show the call you made and the error you received. That is enough to know something upstream refused and not enough to know which of your customer's systems it was or what it objected to. The vendor's portal knows, if it has one and if the customer grants you access, which is two conditions that fail often. The customer knows something is wrong, usually last, usually in the form of a screenshot.

The real problem is the fourth card. Even with all three sources open, nothing connects them: no shared identifier, no shared clock and no shared vocabulary for what happened. That correlation work is where the hours go, and it grows with every system you support.

The record

Five things, for every call

A log is only useful if every entry has the same shape, because that is what makes it searchable, comparable and countable. Maesn writes one record per API call with the same five fields whether the call went to a system with a modern REST API or to one that answers in files, which is the difference between a trail you can follow and a pile of vendor-specific messages.

One record per API call
endpointWhich call was made, so the action is unambiguous.
responseHow the target system answered, normalised into one shape across systems.
timestampWhen it happened, which is what makes a sequence of events reconstructable.
targetSystemWhich of the connected systems the call went to.
accountKeyWhich customer connection it belonged to, so one tenant can be followed.
What the record is not

It holds that a data transfer took place, not the data that moved. The payload itself is not stored.

The last strip is the part worth reading twice. The record establishes that a data transfer happened, with which endpoint, to which system, for which connection and when. It does not keep the payload, which is how this coexists with not storing customer data. You can prove what your integration did without Maesn holding what it moved.

Your side of it

The same trail, in your own logs

Six documented fields worth storing on your side, so your records line up with Maesn's instead of sitting beside them.

Signal
context.targetSystemWhich of the connected systems this call actually went toevery error
context.unifiedApiWhich Unified API the call was made againstevery error
context.timestampWhen the call was processed, so you can line it up with your logsevery error
meta.warningsWhich fields the target system does not use, named instead of dropped in silenceresponses
downstreamErrorsWhat the target system itself reported, in its own words, kept verbatimsystem errors
information[]What a background task reported, one entry at a time, each with a timestampasync tasks

None of these needs a request of its own. If you store context alongside your own error records, a failed sync is already attributable to one system at one moment, and a support question becomes a lookup. That shift lands hardest with customer success teams, because the answer stops depending on who remembers the last incident. If you surface meta.warnings anywhere a user can see it, the field a target system silently ignores stops being a discovery you make in a report six weeks later.

Background work leaves the same kind of trail. An asynchronous operation reports its progress through the task it hands back, entry by entry rather than as a single verdict, and every webhook event names the object it concerned and arrives signed, so an event that surprises you can be traced to a record and to Maesn.

Monitoring

Watching the systems you did not build

The failures that hurt most in an integration business are the ones at a vendor you have no account with. A system is slow for an hour, an endpoint returns errors after a release, a maintenance window nobody told you about lands in the middle of your nightly sync. You find out from a customer, which is the worst available channel.

Maesn learns about an outage from the vendor rather than from an alert of its own and passes it on to the tenants running on that system, so the notice does not have to start with your customer. What reaches your application is not silence but a typed error: a system that is temporarily unavailable arrives as a 503 with the service_unavailable type.

Retrying and pacing are narrower than that. Maesn retries and paces on the asynchronous endpoints. Everything synchronous passes the target system's 429 straight through, so the backoff and the schedule stay yours. That is the difference between a sync you can retry deliberately and one that disappeared.

A target system
Starts failing or slows down
maesn
Names the system and notifies
Your app
A typed error, not silence
Why it matters

One question, one place to answer it

Building it yourself
  • Correlate your logs with each portal
  • Guess which system a failure came from
  • Learn about outages from customers
  • Discover dropped fields in a report
With Maesn
  • The system named in the response
  • Requests, responses and webhooks logged
  • Connected systems watched for you
  • Ignored fields named as warnings

Support cost is the quiet part of an integration's total cost. It does not appear in the build estimate, it arrives afterwards, and it scales with the number of systems and the number of customers rather than with the amount of code. The single biggest lever on it is being able to answer where something happened without asking anybody.

That is why the system is named in the response rather than left for you to infer, and why a field a system does not use is reported as a warning instead of dropped in silence. It is the same principle as the common data model: the differences between systems are absorbed, and the ones that still matter to you are made visible on purpose.

Unified Logging & Monitoring FAQ

Common questions

What exactly does Maesn log?

One record per API call, in the same structured form every time: the endpoint that was called, the response, the timestamp, the target system and the account key. That is enough to reconstruct what happened at what time for a given customer connection. The records are available in the Maesn portal and through the API.

How long are the records kept?

It depends on the plan: 30 days on Start and Scale, 90 days or more on Enterprise. Retention is listed with the rest of the plan comparison, because how far back you can investigate an incident is a commercial question as much as a technical one.

Do the logs contain our customers' data?

No. The record establishes that a data transfer took place, with the endpoint, the target system, the account key, the timestamp and the response, and it does not keep the payload that moved. That is how logging and the commitment not to store end-customer data hold at the same time: you can prove what your integration did without Maesn retaining what it carried.

Why does a unified log matter more than a log?

Because the systems' own responses and messages have nothing in common. Without normalisation, one record per system means one format per system, which is not searchable, comparable or countable across an integration. Unifying the shape first is what turns a pile of vendor messages into a trail you can follow.

How do I tell which system a failure came from?

Every error carries a context block with targetSystem and unifiedApi, plus a timestamp for when the call was processed. That is the field to log on your side, because it turns a failed sync into a specific system and a specific moment instead of a stack trace that only describes your own code.

Can I see what the target system itself said?

Yes. When the error type is target_system_error, the system's own error response and status are passed through in downstreamErrors, verbatim. You get a category to branch on and the provider's own wording to debug with, rather than a summary of it.

How would I know a field was ignored?

Responses can carry meta.warnings, with entries such as a field not being used by the target system. That is the case that otherwise goes unnoticed for weeks: the write succeeded, the object came back, and one value quietly never arrived on the other side.

How do I follow a long running operation?

Asynchronous operations answer with a taskId, and GET /asyncTask returns the status along with an information array. Each entry carries a message, a type and a timestamp, so a background write leaves a readable trail rather than ending in a yes or no.

Are webhook events traceable to a record?

Every event names what it was about through eventType, resource and resourceId, and arrives signed, so you can tie an event to an object in your own data and verify that it came from Maesn before acting on it.

What happens when a connected system has an outage?

Maesn learns about it from the vendor rather than from an alert of its own and tells the tenants running on that system. On your side a temporarily unavailable system surfaces as a 503 with the service_unavailable type, which is a signal you can act on rather than a request that vanishes. Retrying and pacing are narrower: they happen on the asynchronous endpoints, and everything synchronous passes the target system's 429 straight through, so the backoff stays on your side.

Why does this matter more with a Unified API than with one integration?

Because the number of places a failure can originate grows with every system your customers connect, while your own logs keep describing only your side. One integration is two logs and one portal. Ten integrations without a shared vantage point is a support process that gets slower every quarter.

Build once on the Unified API.

See how unified logging and monitoring works for your integration, or dive into the technical reference.