Data moves between your systems, and the numbers agree.
Etalon collects from banks, advertising accounts, trackers and internal tools, keeps one canonical copy of the records, checks that the figures agree across systems, and delivers the result where it is needed — another system, a warehouse, a dashboard, a Slack message.
Collect, agree, deliver.
Collect
Scheduled pulls, signed webhooks and file drops land every record in one place, with the raw payload kept next to the parsed row.
Agree
Sources are matched on the keys they share. The difference between two systems becomes a column you can sort, filter and alert on.
Deliver
The same records go onward: into another system through its API, into a warehouse, into a spreadsheet, into a Slack message at nine in the morning.
Four systems. Four numbers.
Illustrative figures
Each of those numbers is correct inside the system that produced it. The advertising account counts what it delivered, the bank counts what it settled, the tracker counts what it attributed, the books count what was recognised.
No system owns the number that spans all four. Once a month somebody exports four files, lines them up by hand and reports the result, then does the same work again in thirty days, because none of it was written down anywhere a machine can read.
That number lives in Etalon and stays current.
Five stages, the same for every source.
A bank statement, an advertising account and a task tracker travel the same path. Only the connector is written per source.
- 01
Connect
Credentials are entered once, sealed with authenticated encryption and kept inside your own instance. OAuth sources refresh themselves and persist the rotated token, so a connection made in March is still live in December.
- 02
Pull
Every connection carries its own schedule in the database and is claimed under a lease before anything is fetched. Two processes can run side by side and each account is still pulled once.
- 03
Canonicalise
Each record lands as a typed row beside the payload it came from. Everything is kept, so any figure on any screen opens down to the exact response the source returned.
- 04
Agree
Two sources are joined on account and period, campaign and day, order and payment. The gap between them is stored, watched and reported like any other measure.
- 05
Deliver
Rows are pushed into the systems that need them, exported on a schedule, rendered as a pivot in the browser and announced in Slack when a figure crosses a threshold you set.
Anything with an interface can be a source.
Etalon connects through whatever a system offers: a REST API, an OAuth application, a signed webhook, a scheduled file drop, or a login and a monthly statement that somebody downloads. The categories below are the shapes we meet most often; which providers sit inside them is decided by your stack.
Banking
Cards and wallets
Crypto and exchanges
Advertising accounts
Attribution and mobile
Product analytics
Accounting and ERP
CRM, tasks, forms
Anything with an interface
We build the connector
Building the integration is part of the service. You name the system, we write the connector into your instance for a fixed fee, and from that day it is scheduled, monitored and alerted like everything else in the pipeline.
Records go back out to the systems that need them.
Etalon writes the same records forward, on a schedule or the moment they land, and gives every delivery the retry and alerting it gives a pull.
Records are written through its own API, mapped to its objects and idempotent on retry.
A schema you can query directly, kept current on the same schedule as the pull.
XLSX and CSV on a schedule, to a bucket or an inbox, matching what the screen shows.
A signed webhook per event, with delivery retried and dead-lettered like everything else.
Cards on an event, threshold alerts, a morning digest of what moved overnight.
Spend and settlement disagree
Paid social+175.20
Periodthis month
POST /your-endpoint X-Etalon-Signature: sha256=…
{
"event": "record.upserted",
"source": "advertising",
"occurred_at": "2026-07-31T09:00:00Z",
"record": {
"account": "paid-social",
"campaign": "prospecting",
"day": "2026-07-30",
"spend": "1284.40",
"currency": "USD"
},
"delivery": { "attempt": 1, "idempotency_key": "a7f1…" }
} Pivots, charts and exports over the same tables.
Rows nest as far as the data goes, columns are periods you can regroup by day, week, month or quarter, and every subtotal is computed inside the database over the full set of rows. Any cell opens down to the records behind it.
Spend by channel and campaign
| Channel / campaign | Apr | May | Jun | Total |
|---|---|---|---|---|
| Paid search | 18,420 | 19,980 | 21,340 | 59,740 |
| Brand | 4,120 | 4,260 | 4,510 | 12,890 |
| Generic | 9,880 | 10,640 | 11,300 | 31,820 |
| Competitor | 4,420 | 5,080 | 5,530 | 15,030 |
| Paid social | 22,140 | 20,860 | 24,410 | 67,410 |
| Prospecting | 14,980 | 13,420 | 16,900 | 45,300 |
| Retargeting | 7,160 | 7,440 | 7,510 | 22,110 |
| Affiliate | 6,300 | 6,740 | 6,120 | 19,160 |
| Total | 46,860 | 47,580 | 51,870 | 146,310 |
Spend and cost per acquisition
Illustrative figures
Views are written down
A report is a file with its query, axes and measures. It is reviewed and versioned with the rest of your code, and the same definition backs the screen, the export and the digest.
Exports match the screen
XLSX and CSV carry the filters that were applied when you clicked, so the file mailed to a board member holds the figures the dashboard showed.
Share what you choose
A view can be granted to a person with a row filter attached, or published as a link with its configuration frozen.
Or query it yourself
The canonical tables are ordinary Postgres. Point your own tool at a read-only role and work with the data directly.
Every pull is leased, retried and accounted for.
Each connection is claimed with a database lock and a short lease before anything is fetched, then rearmed in the same transaction. Two instances can run side by side and every account is still pulled once. A deploy in the middle of a run costs one retry.
Failures back off and retry on their own. When the attempts are spent the work moves to a dead-letter queue and raises an alarm, so a dropped webhook or a missing statement is visible the same day.
Alerting is streak-gated. One blocked request is retried without an alert, two consecutive failures on the same account raise one, and the recovery closes it. Heartbeats go out on a timer and an external watchdog checks that they arrive, so a pipeline that dies quietly is caught as well.
Built in Rust, top to bottom.
Connectors, scheduler, reconciliation, reporting and the web interface are one Rust program. One process to deploy and one to watch; reports are computed in Postgres next to the data, and a pull that runs every few minutes keeps running for years.
One binary
The whole service compiles to a single statically linked executable with no runtime and no garbage collector.
Cold start under a second
A deploy or a restart is back in service within a second, which is what makes an instance per client practical.
Tens of megabytes at rest
It idles on the smallest instance your cloud sells and spends its day waiting on slow upstreams.
Thousands of records a second
Parsing and upserting are bounded by the database, and the database is right next to it.
Decimal money
Amounts are exact decimals from the wire to the screen, through every sum, rate and conversion.
Async I/O
One process holds hundreds of open connections while a bank takes its time answering.
Least privilege, by construction.
Credentials stay in your instance
Tokens are sealed with authenticated encryption under a master key held in the environment and opened only for the request that needs them.
Reporting connects read-only
Reports connect through roles without write permission, inside read-only transactions. A view has no way to touch a ledger.
Access is per view, per row
People are granted individual views, optionally with a row filter the server applies to every query they run.
Every run is logged
Each run is recorded with its outcome, duration and record counts, kept as long as you need it and pruned on a policy.
What comes with an instance.
- Access grants per view
- Audit log of every run
- Backfill on demand
- Chart tiles
- Currency conversion at event date
- Dead-letter queue
- Drill-down to the raw payload
- Encrypted credential store
- Filters and parameters
- Grain switching by day, week, month
- Heartbeats and external watchdog
- Idempotent writes downstream
- Multi-entity, multi-currency
- OAuth token rotation
- Pivot subtotals in the database
- Prepared-statement binding
- Retention policies
- Rolling re-pull windows
- Row-level filters
- Scheduled exports
- Share links
- Signed inbound webhooks
- Slack digests and alerts
- XLSX and CSV export
Three ways in.
Close the month with the numbers already agreed
Several legal entities, several countries, accounts across banks, cards and crypto. Balances and movements arrive on their own, transfers between your own accounts are recognised as transfers, and the closing figure is reconciled against the bank while the month is still running. By the time the month closes, the reconciliation has already run every day of it.
Unit economics computed on data that matches the money
Spend from every advertising account, installs and events from attribution, revenue from the books, settlement from the card that actually paid. Cost per acquisition and return on ad spend are computed once, on data that agrees with the money, and an alert arrives when a campaign drifts past its target for two days running.
One instance per client, run by you
Agencies and studios carry a dozen clients, each with their own accounts, currencies and reporting. Every client gets an isolated instance with their own sources and access rules, and the monthly client report arrives as a scheduled file and a Slack digest.
Tell us what your stack looks like.
Send the list of systems you run and what should flow between them. We will come back with what connects today, what we build for you, and how long it takes.