Security
How your invoices are protected
Supplier invoices say a lot about a business: who you buy from, at what price, and how much. This page sets out what protects them, and only what we can show is in place. Where something isn't built yet, it says so.
Where your records live
Your records are stored in Australia. The database and the file storage are in Sydney, and invoice documents are read by Microsoft Azure in its Australia East region.
Some of the services we rely on are overseas, mostly in the United States, and see parts of your data along the way: Postmark receives invoice emails and delivers the emails CostCode sends, Anthropic answers questions put to the assistant, sorts invoice lines into trades and works out the columns of a PDF price list, and Inngest coordinates the processing pipeline (anything read from an invoice is encrypted with a key only our servers hold before it reaches Inngest). The privacy page lists every service and exactly what each one sees.
A price list you import as a spreadsheet is read in your browser and saved to your records in Sydney; no outside service sees it. One you import as a PDF is stored in Sydney while Azure reads it in Australia East, then deleted. The text of its tables (item words, codes, units and prices), never the PDF, goes to Anthropic in the United States so it can say which column is which, and nothing becomes an agreed rate until someone on your team confirms it.
Bank details printed on an invoice stay in the stored original. CostCode doesn't pick them out or check them, so it can't yet tell you when a supplier's bank details change.
Separation between customers
Every table that holds customer data carries the organisation it belongs to, and the database itself refuses to return a row to anyone outside that organisation, on every query. It doesn't depend on application code remembering to filter.
That is tested, not assumed. An automated test fails the build if any table is added without that protection, and another runs every migration against a real Postgres database and reads every table as a signed-in stranger and as an anonymous visitor, expecting nothing back.
The website holds no database key that can get around those rules. Only the background pipeline that reads and checks invoices holds one.
Our support console holds no database key either. Staff sign in to it with a password, and repeated failed sign-ins are blocked. It asks the pipeline for what it shows, in a request signed with a key only the console holds and naming the member of staff asking. The pipeline answers with account details and counts, shows the contents of your records only while you have support access switched on, and records every request before it answers.
Original documents
Each invoice is stored exactly as it arrived, in a private storage bucket, under a name made from a fingerprint (a SHA-256 hash) of its contents. Nobody signed in to CostCode can overwrite or delete an original, and that is tested too. Originals are removed only when you delete your organisation.
What reaches your suppliers
Nothing sends itself. Email to suppliers is off for every new organisation until an owner or admin turns it on. Even then, a query goes only when a person in your team reads it and presses send, and the database records who pressed it and when: it refuses to mark a message sent on anyone else's behalf.
A query can only quote evidence the supplier can check for themselves: the rate agreed with them, the arithmetic on their own invoice, GST, the unit, or a duplicate of their own invoice. What you paid anyone else, and anything derived from another business, can never appear in it. That rule is built into the code, with a test whose only job is to fail if it is ever weakened.
And a misreading is never an accusation. Before any check runs, our reading of an invoice is reconciled against its own totals. If it doesn't reconcile, a person in your team looks at it first, and no finding is raised against the supplier from it.
The audit log
Every consequential action (a clearance, a dismissed finding, a released hold, a query sent, a settings change) is written to an append-only log: who did it, what changed, and when. The database refuses to edit or delete a row in it, for everyone, including us. It goes only when you delete your organisation, and a record that the deletion happened is kept.
Encryption and sign-in
Traffic to CostCode and between our services is encrypted in transit (HTTPS/TLS). Supabase, which holds the database and files, encrypts them at rest, as it documents for its platform.
Sign-in is by a one-time code sent to your email, or a password if you set one. Passwords are held by Supabase as one-way hashes; nobody at CostCode can read them. Two-factor sign-in isn't available yet.
The assistant
The assistant sends something only when someone in your team asks it a question. Then the question and the records needed to answer it (supplier names, invoice totals, the words on invoice lines, agreed rates, and which of your team has a held invoice) go to Anthropic's API in the United States. Invoice documents are never sent, and Anthropic does not train its models on this data. An owner can turn the assistant off for the whole organisation in Settings.
Anthropic also sorts invoice lines into trades, such as concrete or hire, so we can show where the money goes. The description and unit of each line we can't sort ourselves go to Anthropic's API in the United States: as an invoice is read, and once for lines on invoices read before we began sorting them. We don't send the supplier's name with them, though a line's own words can name a brand, an address or a person, and we never send the invoice document. Anthropic does not train its models on this data.
Price data without your name on it
We are building a record of prices from checked invoice lines, to improve the product over time. It isn't collecting yet, and starts only once our terms say so. When it does, it records a price, a unit, a normalised description and a trade, with no names, ABNs or totals, in a completely separate database written only by our background pipeline, which holds the one key to it. The website has no way to reach it. An owner or admin can leave their organisation's prices out at any time in Settings, under Account.
Buyer and supplier identities are replaced with keyed hashes before a row is written, and there is no function anywhere in the system that reads this data back. Nothing drawn from it is ever shown to another customer or to a supplier. The privacy page explains what happens to those rows when you delete your organisation.
The free invoice check
A file put through the free check on our website is read in memory, by Azure in Australia East, and not saved. The privacy page has the detail.
What we don't have yet
We hold no security certification (such as ISO 27001 or SOC 2), and two-factor sign-in is not built. The sorting of invoice lines into trades with Anthropic can't yet be switched off for an organisation. We'd rather say so than let you assume otherwise.
Reporting a problem
If you think something has gone wrong with your data, or you've found a security weakness, write to hello@costcode.co. We'll tell you what happened.
Got a supplier invoice handy? Check it now.
About ten seconds. No account. We don't keep the file.
Or start free: 20 invoices a month, no card