How it works
- Your user installs Habeas and enables the sources they care about (their bank, their broker).
- Your app asks for a connection. Habeas opens its own consent screen. Nothing runs until the user approves it there.
- Data arrives at your endpoint, already normalized, as new items appear. You acknowledge what you actually stored; the rest is retried.
Two ways to integrate
Pull — you fetch
You propose a specific source, and once the user approves it you can trigger collection whenever you want (a "Sync" button in your UI).
await habeas('propose-workflow', {
source: 'ing-es',
sink: {
type: 'http',
url: 'https://your-app.com/ingest',
headers: { 'x-pair-token': '…' },
},
});
// then, later:
await habeas('collect', { grantId });
Push — they send
You register only as a destination, with no source and no permission to fetch anything. The user routes whichever sources they want to you, from Habeas.
await habeas('register-sink', {
sink: {
type: 'http',
url: 'https://your-app.com/ingest',
headers: { 'x-pair-token': '…' },
},
});
Both are documented in external-hooks.md. Most apps start with pull and add push later.
What you receive
- Normalized records, not raw HTML: dates, amounts with sign, description, balance, an id for de-duplication, and the account they belong to. Each record also carries the raw source fields, so nothing is lost.
- Banking and brokerage. Transactions, and for brokers, trades and cash movements (units, price, fees, withholding, instrument).
- Only what is new. Habeas keeps a per-destination ledger, so re-syncing does not re-send what you already have.
- Per-record acknowledgment. Your endpoint replies with the ids it actually incorporated; anything else stays pending and is retried. No silent data loss.
To see the exact shape before writing anything, there is a worked sample: canonical-record.json. Eight movements — a Spanish IBAN account, a card, a US routing-and-account number and a UK sort code — showing which fields are always present, which are conditional, and how an account identifies itself where IBANs do not exist. The field-by-field rules are in RECORD-CONTRACT.md.
The rules that make this safe
These are enforced in code, not promised in a contract:
- Origin-bound. The endpoint's host must equal your own origin. A site can only ever route data back to itself. There is no allowlist because there does not need to be one.
- Explicit consent. Nothing is registered or runs until the user approves it on Habeas's own screen, and an existing permission can never be widened silently.
- No credentials, ever. Habeas never reads, stores or types your user's passwords. They log in themselves, including any MFA.
- Revocable. The user can drop any integration at any time from Habeas's settings.
The bank your users need: they can add it themselves
The obvious objection to any catalog is "my users' bank isn't in it". Here's the part that matters: nobody has to wait for us to add it.
Reading happens inside the account holder's own session, which means the person who can teach Habeas a new bank is whoever already banks there — not us. So the extension ships a recorder for exactly that, in Settings → Record & contribute:
- The user browses their bank as they normally would, signed in, while it records.
- Habeas drafts the source automatically from what it saw — endpoints, paging, fields — and the user maps anything left over in a visual editor, with a Test button that runs against their live session so they see real rows before sharing anything.
- What reaches us is redacted: every value is replaced by a type placeholder and only the structure survives. We author and verify the source without ever seeing their data.
- Once published, that source works for everyone — your users and ours.
No code is written by anyone, and a source is a definition file rather than a program, which is why this can be a commons at all. If you'd rather write one by hand, that path is open too: AUTHORING-SOURCES.md and ASSISTED-AUTHORING.md.
This is where collaborating actually pays off. Adapters are shared plumbing; the product you build on top is where you compete.
What this is not
So you can decide with the real trade-offs on the table:
- It is not silent background sync. Your user must have a live session; if there is none, Habeas surfaces the login tab and waits for them. That is a design decision, not a missing feature.
- Sources need maintenance. When a service changes its site, its definition has to be updated. The difference is that you can fix it yourself instead of waiting for a vendor's roadmap.
- It runs on desktop browsers, where the extension lives.
- Each service has its own terms, and complying with them is the user's responsibility. Habeas operates on a person's own data, in their own session.
Start here
Integration guide API reference Source (AGPL-3.0)
Habeas is licensed under AGPL-3.0: if you improve it, the improvements come back to the commons. Cuéntamo was the first app to integrate it, and it is not meant to be the last.
The source definitions are deliberately different. Every definition in the catalogue is in the public domain under CC0-1.0, and the guide prose under CC-BY-4.0. A definition only records how a service has arranged data that already belongs to its user, so build on it in anything at all — commercial or not, with credit or without.
Building something and hit the same wall? Open an issue on GitHub, or write to hola@habeas.dev.