Muntin

About Muntin

Payroll register for company groups with more than one legal entity

We built this for the person two weeks into a payroll implementation, sitting next to a consultant who is mapping pay groups. The company has two registered entities: the operating company, and a subsidiary incorporated last year. The plan was quoted before anyone checked where that second entity would sit, and it turns out to sit outside the plan, as an add-on, next to the API that was supposed to push cost centers into the ERP. So the subsidiary stays on the spreadsheet it was already on, and every month somebody reconciles two payroll truths by hand before finance sees either one.

Muntin sits above whatever runs each entity's payroll. Its core object is a register: one row per legal entity, with its number, pay calendar, currency, cost center tree and whoever runs it today. Every period each entity's file arrives and is mapped onto one fixed row contract, and the original is kept beside it byte for byte, because a posted journal has to be traceable to the file it came from.

Then the same checks run across all the entities at once: one person on two registers, a person on none, a cost center finance never published, a leaver still being paid, a file that never turned up. Anything that fails goes to a queue with a named owner, and the period will not close while one row in it is unresolved. When it closes, the journal posts per entity, the headcount webhook fires, and the period is frozen. A correction afterwards is a new version, never an edit.

Two jobs in there are dirty enough that rules only get part of the way, and that is where the machine learning does real work. The first is reading a payroll file nobody has seen before. A header dictionary handles the tidy exports and gives up on the first file from a new bureau, or on the spreadsheet where the header row is three rows down and two columns are merged. So a fine-tuned classifier reads the header together with a fingerprint of the column's values, which is where most of the signal is: magnitude, sign, currency formatting, whether it sums to another column. The second job is deciding whether two rows in two entities are the same person. There is no shared key: someone who transferred in March has a new payroll ID and a name written in a different order by a different bureau. An embedding model proposes candidates over name, date of birth, the last four of the account and role.

The models decide nothing. A mapping is applied once an operator confirms it, an identity match only above a fixed threshold and only after a person confirms, and below it nothing is guessed: the row stays unresolved and the close waits. Being told two records are one person when they are two puts money against the wrong entity and ends up in a filed journal, which is worse than a close that waits an afternoon. Every one of those confirmations is written back as a labeled pair, and the two corpora they fill are kept apart because they hold different things. Column headers and the statistics of their values carry no cell data, and that corpus is ours: it is what makes the next bureau's template cheaper to map than the last one was. Identity pairs are employee personal data, so they are partitioned per customer, never pooled, and never used to train anything another customer touches.

The work comes in bursts, for three reasons. A new group arrives with up to 24 months of closed periods across every entity, and the whole backfill is parsed, classified, embedded and matched in one pass. Payroll periods cluster on the last two working days of the month and the first three of the next, so nearly every customer runs its heaviest reconciliation inside the same 72 hours and the rest of the month is quiet. And a new embedding model version means re-embedding everything, because a match that cleared the threshold last month has to clear it the same way this month. Sizing for that peak means paying for capacity that does nothing for three weeks in four.

Most of the money goes two places, both on AWS in Frankfurt, and the larger one is GPU hours. Both models run on EC2 GPU instances there, taken on demand, by the hour, raised for a backfill or a month-end and dropped between them. The second line is storage, and unlike the first it only ever grows: every source file sits in S3 in the same region beside the rows mapped from it, with the entity register, the locked period records and the immutable log, and files, rows, check results and locked periods are kept for the life of a subscription and 24 months after it ends, because a posted journal is audited long after the software is switched off. It is not an optimized bill. The subscription is flat at 1,290 euro a month for the whole group whatever shape that group turns out to have, so a group that arrives with forty entities and eleven bureaus is unprofitable for us, and we honor the published price anyway.

From Q3 2027 the fine-tuned classifier and the embedding index for identity matching run on reserved EC2 GPU capacity in Frankfurt, with on-demand capacity kept alongside for month-end and for onboarding backfill: the reservation buys the floor, the on-demand hours buy the peak. The third, smaller line is training. The column classifier is retrained on Azure Machine Learning in Microsoft's Germany West Central region, which is Frankfurt too, and that bill grows with every new bureau's file shapes. Only the column corpus goes there, because it holds header strings and value fingerprints and no cell values, names or salaries; identity pairs are employee personal data and stay on AWS. We are a German GmbH handling names, salaries and bank fragments under GDPR, often in front of a works council, so both models run on compute we operate, no payroll data goes to a hosted model API, and there is no model vendor in the path. Nothing is processed outside Frankfurt.

Founders

Warren Kilbride

Founder

Ran HR operations through two acquisitions, and spent nineteen monthly closes reconciling a subsidiary payroll spreadsheet by hand against a suite with no row for it.

Marion Fenwick

CTO

Built ingestion pipelines for bank feeds, and learned there that the hard part is never the parse. It is proving which file a posted figure came from.

Garrett Loomis

CFO

Signed off a revised implementation quote carrying two line items nobody had scoped, then could not tell his own board which entity the headcount number covered.

Company

entity
Muntin
registered
Muntin Systems GmbH, Katharinenstrasse 17, 04109 Leipzig, Germany
contact
[email protected]

← BackPrivacyTerms

Your request has been received.

Expect a message from Muntin. It goes to the address you gave.