maesn
Use case

Sync expenses in the shape each system requires

Your product knows what was spent, by whom and on what. What it does not know is which of three field names this customer's system uses for the ledger account, or whether the line has to carry the net amount or the gross. Maesn delivers that, then posts the expense.

One expense lineexpenseLines[]
One slot, required everywhere
The ledger account this expense is booked to
and it is called
  • accountId4 systems
  • accountNumber2 systems
  • accountCode1 system

Across the connected systems, 7 accept an expense you write. They agree on what the line needs and not on what to call it.

Trusted by winning software teams
HubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinProvetHeroHolviLanes & PlanesHubSpotTipaltiPaywiseRallyQredNordhealthFindityFintoClockinProvetHeroHolviLanes & Planes
The problem

One expense object, seven different contracts

Writing an expense is a single call on every system that supports it. What that call has to contain is different on all seven, and the differences are not cosmetic.

The seven systems that accept a written expense today
Business Central
Account on the lineaccountId
Required amounttotalNetAmount
Booked againstsupplierId, required
DATEV Unternehmen Online
Account on the lineaccount.number
Required amounttotalGrossAmount
Booked againstnot in the request
Exact Online
Account on the lineaccountId
Required amounttotalGrossAmount
Booked againstsupplierId, required
Lexware Office
Account on the lineaccountId
Required amounttotalGrossAmount
Booked againstsupplierId, required
QuickBooks
Account on the lineaccountId
Required amounttotalNetAmount
Booked againstsupplierId, optional
Twinfield
Account on the lineaccountNumber
Required amounttotalNetAmount
Booked againstnot in the request
Xero
Account on the lineaccountCode
Required amounttotalGrossAmount
Booked againstsupplierId or customerId
The middle column is the one that costs money: three systems require the net amount on the line and four require the gross, and the difference between the two is exactly the tax. Send the number you happen to hold and the booking is not close to right, it is wrong by the tax on every line.

The object itself is simple and it is the same everywhere. A header says when the money moved and in which currency; a line says which ledger account the spend belongs to, how much it was, and at what tax rate. Every system that accepts an expense wants exactly that much. No two of them want it in the same words.

The account is the visible case. All seven require the line to name one, and between them they call it accountId, accountNumber and accountCode. That costs you a mapping table and nothing more. The amount is the one that goes wrong quietly, because both figures are perfectly valid numbers and only one of them is the one that system asked for. A line sent gross where the net was required is not rejected, it is booked, and it is booked wrong by exactly the tax. That the tax rate is itself often published without any rule for applying it is the second half of the same problem.

On top of the shared shape, every one of the seven adds something none of the others asks for. QuickBooks wants a payment type, and the account on the header has to be of the matching kind. Xero wants to know whether the document is an expense or a refund, and it wants either a supplier or a customer rather than neither. Exact Online and Twinfield want a journal code. Lexware Office wants a document number and a tax rate percentage on every single line, which is worth pairing with a second fact about that system: it is the only one of the seven whose tax-rate read is marked on demand rather than supported today. None of these is unreasonable. Together they are the reason an expense integration is rarely finished after the first system.

How Maesn solves it

One connection for the accounts, the rates and the dimensions

Everything an expense has to reference comes back in one shape from every connected system, which is what lets your users map their spend onto their own accounting setup once instead of once per vendor.

Two documented routes into a ledger

Of the 29 connected systems, seven accept an expense and ten accept a journal entry, which is the route the guide mentions in its closing line. Only five accept both, so this is not a fallback for the weaker systems: DATEV Unternehmen Online and Lexware Office take an expense and no journal entry, while five others take a journal entry and no expense. Counting either route, twelve systems can receive spend from your product today.

The chart of accounts is the load-bearing read of this use case, and it is also the strongest one: the same normalized object is readable on nineteen systems, and on every single system that accepts an expense. What varies is how much each one puts in it. The field the guide suggests grouping by, so that a user sees expense accounts rather than a flat list of hundreds, appears in seven of those nineteen documented field lists, and the parent reference that would let you draw the ledger hierarchy appears in two. Neither gap stops the use case. Both decide how good the account picker in your product can be for a given customer, which is exactly the kind of thing worth knowing before a design review rather than after one.

The rest of the chain is ordinary once the connection exists. Your customer authorizes it once through one flow whichever system they run, tax rates and suppliers arrive as the same objects everywhere, and reading only what changed since the last run is how a cached chart of accounts stays honest while your users edit theirs. Where a system holds something the shared model has no field for, reaching past the model is documented rather than improvised.

What a connection cannot do is invent the data. Dimensions are the honest example. Three systems publish a readable list of them today and most of the rest carry an on demand marking in their own documentation, which is a marking and not a promise. Separately, exactly two systems document a dimension field on the expense line itself, and they are not the same two. So a cost-centre feature is buildable, and it is buildable for named systems rather than in general, which is a much better sentence to put in front of a customer than an assurance that everything is supported.

What you get

The expense lands where their accountant already looks

The result of all of this is unglamorous and it is the point: spend that occurred in your product appears in your customer's ledger, on their account, at their rate, without anybody exporting a file. The clearest way to show what that takes is one system where the ordinary words do not apply.

GET /accountsWhat comes back
nametypeand nothing else

Two fields, and type takes one of three values: CASH, ACCOUNTS_RECEIVABLE, ACCOUNTS_PAYABLE. No number, no class, no balance. This is a list of ledger folders rather than a chart of accounts, which is what the guide means when it notes in passing that for DATEV the endpoint only provides account ledger names.

the same value, unchanged
POST /expenses/asyncWhat it requires
account.namegeneratorNamecurrencytotalGrossAmounttransactionDate

The folder name goes straight back in, and it has to be one of type CASH. The response is a task id rather than a booking, so GET /asyncTask is where you learn whether it landed. The synchronous endpoint still lists this system and marks it deprecated, pointing here.

DATEV Unternehmen Online does not hand out a chart of accounts at all. What comes back is a short list of ledger folders with a type, and the write wants one of those names back, of the cash kind. A product built on the assumption that every system returns numbered accounts has nothing to show its user here. A product built on what each system actually returns has a list its user recognises and a posting that lands, which is the same difference the DATEV integration makes on every other use case too.

The second half of that panel is the part most integrations discover late. This write is asynchronous: the response is a task id, and a separate call tells you whether the booking landed. Handling that properly means your user hears about a failure minutes later instead of never, and it is far cheaper to build for at the start than to retrofit onto code that assumed an answer would arrive with the request.

Two smaller things belong to the outcome as well. The receipt travels with the expense on six of the seven systems, because the write is a multipart request and takes the file alongside the data, so the document your user photographed sits where their accountant expects it rather than in a folder somebody has to reconcile later. And the trigger stays yours: whether an expense syncs the moment it is approved, in a nightly run, or only when somebody presses a button is a decision about the workflow your users already have, not about the connection.

Proof

Expense management, embedded in their customers' accounting

Findity puts expense sync inside their partners' products.

Maesn has helped us build integrations with accounting systems, allowing us to focus on other priorities in our roadmap. We are especially pleased with the support we have received whenever we needed extended functionality in an integration that Maesn has arranged for us.
Per Q.
CTO, Findity

Findity builds expense management as a white-label and API product, which means their integrations are not theirs alone: every partner who embeds them inherits whatever accounting systems Findity can reach. That is this use case at its most demanding, and the part of the quote worth reading twice is the second sentence, about extended functionality being arranged when an integration needed more than it had. Systems like Lexware Office, Xero and QuickBooks all accept an expense and disagree about nearly every field of it, which is the work that gets absorbed here. The customers who have a published case study are a different set, and this one is a quote rather than a study.

Key facts

Every step of the sync, counted per system

Both write routes first, then everything the expense has to reference, counted from the per-system documentation.

Across the 29 connected systems
What you needTodayOn demandSystem cannot
Expenses, writing7193
Journal entries, writing10118
Chart of accounts, reading1982
Suppliers, reading1928
Suppliers, writing14411
Tax rates, reading12143
Dimensions, reading3179
The two top rows are the two documented ways to get spend into a ledger, and they are not the same systems. Below them the chain that makes an expense correct narrows as it gets more specific: the chart of accounts is readable almost everywhere an expense can be written, tax rates on most of it, and dimensions on three. That last row is why the guide marks its dimension step optional.

The table answers the question that actually decides feasibility, which is not whether expense sync works but how much of it works for the systems your own customers run. Read from the top down it also explains the shape of the guide: the write is narrow, the chart of accounts behind it is wide, and everything that makes a posting more specific gets thinner as it gets more specific.

One row is worth a second look for a reason that is not its size. Journal entries reach more systems than expenses do, and the documentation mentions that route almost in passing, as the simpler way to post spend. For a product whose users only need the amount in the right account, and not an expense document with a supplier and a receipt attached to it, that route is available on systems this one cannot reach. Suppliers are the comfortable rows here, and where they need creating rather than only reading, that is its own documented use case.

Where the line runs

We deliver the structure, you own the categorization

On this use case the boundary is drawn by the documentation itself, which spends its longest step describing decisions it explicitly leaves to your product.

What Maesn delivers
  • Accounts, rates and dimensions
  • One shape on every system
  • The expense, written back
  • The receipt, with the booking
What stays your product
  • The account each expense uses
  • The rules your users configure
  • When the sync happens
  • What counts as an expense

Everything on the left is the connection: the customer's real accounting structure delivered under the same names whichever system they run, and a write that lands as a booking rather than as a file somebody imports. That is the part which would otherwise be one integration per accounting platform, each with its own idea of what an account identifier is.

Everything on the right is your product, and here that is more than usual. The documentation devotes its longest step to categorization and then hands the whole thing over: a single default account for the simple case, conditional rules for the harder one, categorization at the moment of sync, and users overriding whatever was configured. It says the business logic depends on your application, and it is right to. What an expense means, which account it belongs on and who may change that are product decisions that sit close to what your users are actually paying you for.

One thing belongs here because the page it replaces put it in the headline. Maesn does not make spend tax compliant. We deliver the rates a system publishes and write back what your product assembled, and the accounting system it lands in is where the local rules apply, exactly as they did before. Where the spend reaches your users as a supplier invoice rather than as a card transaction, posting bills and their payments is the neighbouring use case with its own endpoints, and the lastModified filter is what keeps the accounts and rates you cached from drifting away from the ones your users see.

An expense that arrives already coded is what stops being rekeyed by financial teams.

Expense Management FAQ

Common questions

What does it take to sync an expense into a customer's accounting system?

One write, and a handful of reads that make the write correct. You authorize the connection once, fetch the customer's ledger accounts, their tax rates and, where they use them, their dimensions, let your users decide how spend maps onto those, and then post the expense whenever it happens in your product. The order matters, because everything before the write exists so that the write lands on the right account at the right rate.

Which systems accept an expense today?

Seven of the connected systems take a written expense, and another five take a journal entry instead, which the documentation offers as the simpler route to the same result. Twelve systems in total can therefore receive spend from your product. The more useful question is usually which rather than how many, because only five accept both routes and the rest accept exactly one.

Why does the required amount differ per system?

Because the systems themselves differ, and the shared model carries both figures rather than picking one for you. Three of the seven require the net amount on the expense line and four require the gross. The gap between them is the tax, so this is not a formatting detail: sending the number you happen to hold produces a booking that is wrong by the tax on every line rather than one that fails loudly.

Does Maesn categorize the expenses?

No, and the documentation is unusually explicit that this is your product's job. It describes a single default account for the simple case, conditional rules such as one account per department for the harder one, categorization at the moment of sync, and users overriding whatever was configured. What Maesn supplies is the raw material for that interface: the customer's real accounts, their real tax rates and their real dimensions, in one shape on every system.

Can we attach the receipt?

On six of the seven systems that accept an expense, yes. The write is a multipart request and takes files alongside the expense itself, so the image or PDF travels with the booking rather than being uploaded separately afterwards. Twinfield is the exception in the documentation, which is the kind of per-system detail worth checking before you promise a feature to a customer on a specific platform.

What about cost centres and departments?

Those are dimensions, and this is the thinnest part of the chain. Three systems expose a readable list of dimensions today and most of the remainder mark it on demand in their own documentation. Separately, two systems document a dimension field on the expense line itself, and they are not among those three. So a product that depends on cost-centre reporting should treat it as a question per system rather than a property of the model.

Do we have to create the supplier first?

It depends on the system, which is why the guide marks that step optional. Three of the seven require a supplier on the expense, one takes it optionally, one wants either a supplier or a customer, and two do not carry a counterparty in the request at all. Where a supplier is required, supplier records are among the better covered objects in the model on both reading and writing, so keeping the two sides in agreement is the least fragile part of this use case.

Is a synced expense tax compliant?

That is not a claim this page will make. Maesn delivers the tax rates the customer's system publishes and writes back the expense your product assembled, and the system it lands in is where the local rules already apply. Which rate belongs on a line, and what a filing has to show, stays with your product and your customer's accountant. If you need something firmer than that for a specific market, ask us directly rather than reading it into a marketing sentence.

What happens when a posting takes longer than a request?

One system posts expenses asynchronously by design: the response is a task id rather than a confirmation, and a separate status call tells you when the booking actually landed. That is worth building for from the start, because a write that returns a receipt and a write that returns a promise need different handling in your product, and retrofitting the second onto code that assumed the first is the more expensive order.

What if a system needs a field the shared model does not carry?

There is a documented route for that. A raw data flag returns the target system's own payload next to the normalized object so you can see everything it holds, and where the model has no field at all, a native call through the pass-through endpoint reaches the system directly on the connection you already have. Neither requires a second integration or a second set of credentials.

Build once on the Unified API.

See how expense sync works for your integration, or dive into the technical reference.