1
0 Comments

Building a Cross-Country Payroll API: The Weird Problems I Didn’t Expect

While trying to figure out the tax deductions of a future possible job last yeah, i started creating my own tax engine for the german salary tax scheme.
-> Because why not?
After that tried to integrate it into more a personal finance context and then started to add different tax systems for other german and english speaking countries to get a unique view for cross country comparison.

1. The “same salary” illusion

I originally thought cross-country salary comparison would be fairly straightforward:

gross salary
→ taxes
→ net salary
→ compare the result

But the deeper I went, the less universal the concept of “salary” became.

A €60k salary in Germany behaves completely differently from €60k in Switzerland, the US, or Austria — not only because of tax rates, but because each country structures social systems, payroll deductions, health insurance, pensions, and benefits differently.

Some systems externalize costs that others include directly through payroll. Some countries rely heavily on employer-side contributions. Others shift more responsibility to individuals.

Very quickly, I realized I wasn’t comparing “salary”.

I was comparing entirely different social contracts.

2. Building the normalization layer

The project eventually evolved into two separate layers:

Country-specific payroll logic

This layer handles the messy local reality:

tax brackets
social insurance
filing classes
pension systems
payroll periods
country-specific deductions

A normalized comparison layer

This layer tries to make outputs comparable across countries:

net income
effective tax rate
estimated disposable income
after-rent comparisons
purchasing power signals

The difficult part was preserving country-specific complexity while still exposing a consistent developer experience.

Internally, the APIs can become very country-specific very quickly.
But externally, developers still expect something that feels coherent and predictable.

That tension shaped almost every architectural decision.

3. The hardest part was not taxes

Surprisingly, the hardest problem was not implementing tax formulas.

The hardest problem was deciding what “comparable” actually means.

For example:

What is the correct definition of “net salary”?

before private health insurance?
after mandatory insurance?
before rent?
after childcare?
including pension obligations?
adjusted for cost of living?

Different countries bundle costs into completely different places.

Germany pushes a large portion directly through payroll deductions.
Switzerland often leaves more visible post-payroll costs.
The US introduces additional fragmentation depending on state and employer structures.

At some point, I realized the technical challenge wasn’t purely mathematical anymore.

It was semantic.

The API wasn’t just calculating numbers — it was trying to normalize different economic systems into something developers and users could reason about consistently.

4. Designing for workflows and AI agents

As the project evolved, I started exposing the calculation layer through:

OpenAPI
MCP endpoints
workflow integrations like Pipedream and Postman

That changed how I thought about API design entirely.

Building an API for automation systems feels very different from building one for frontend apps.

Human users tolerate ambiguity surprisingly well.
Automation systems do not.

Things that became much more important:

deterministic outputs
consistent naming
stable response structures
validation behavior
forward compatibility
structured error handling

One unexpectedly useful experience was integrating Obolus into the Pipedream ecosystem.

The review process forced me to rethink parts of the implementation:

naming conventions
auth handling
request abstractions
action ergonomics
advanced input exposure

It was a good reminder that “good API design” is heavily shaped by the ecosystems your API participates in.

5. Salary comparisons become political very quickly

One thing I didn’t expect was how quickly salary comparison discussions become political.

Once you normalize outcomes across countries, uncomfortable questions start appearing naturally:

How much does housing dominate disposable income?
How much is hidden inside payroll systems?
Which systems redistribute more aggressively?
What actually produces financial freedom?

Two countries can produce the same nominal salary and completely different lived realities.

In some places, taxes are high but essential services are embedded into the system.
In others, nominal income looks stronger, but large costs remain externalized.

Trying to compare outcomes consistently forces you to confront how differently societies structure risk, healthcare, pensions, housing, and labor.

The project accidentally became as much about systems design as software design.

6. What the project became

Originally, Obolus was just a relocation comparison experiment.

Over time, it slowly evolved into something closer to infrastructure for cross-country financial decisions.

Today the ecosystem includes:

payroll calculation endpoints
cross-country comparison APIs
OpenAPI specifications
MCP integrations
workflow automation integrations
developer examples and tooling

The biggest lesson for me was realizing that:
building a calculation engine is only one part of the problem.

The much harder part is designing abstractions that remain understandable across countries, users, and developer ecosystems.

And honestly, I still feel like I’m only scratching the surface of how complicated global financial normalization really is.

posted toAvatar for product Obolus Finanz
Obolus Finanz