The short version
If you read nothing else, read this.
- A customer quote link is a 256-bit random token. There is no sign-in on that page on purpose — a homeowner should not need an account to read their own quote — so anyone holding the full link can open it. It is unguessable, it is not indexed by search engines, and it does not carry your costs or your markup.
- There is no multi-factor sign-in yet. That is the biggest gap and we are not going to bury it: it has its own section.
- Every query the server makes is filtered to the business that asked. A test suite tries to cross that line and fails the build if it ever gets through.
- Your price book cannot be read through any support screen, is never pooled with anyone else's, and never reaches your customer's copy of a quote — it has a section of its own, because it is the question we are asked first.
- Inbox passwords are encrypted with AES-256-GCM and are never returned by any API — not even to the account that typed them in.
- Everything runs on managed infrastructure outside New Zealand.
Customer quote links
Unguessable, not indexed, stripped of your costs, and they stop working.
When you send a quote, that customer gets a link with a token on the end of it. The token is 32 random bytes — 256 bits — from the operating system's cryptographic random source. It is not a job number, a sequence, or anything a person could walk through by changing a digit.
There is no password on the page, and that is a decision rather than an oversight. A homeowner deciding on a re-roof should not have to create an account to read what they are being asked to pay. So the honest answer to "can anyone with the URL open it?" is yes — the same as a bank's secure document link or a shared Google Drive file. What matters is everything around that:
- It cannot be found. The quote pages carry
noindex, nofollow, so they stay out of Google. There is no listing, no directory and no way to enumerate tokens. - It is not your full quote. Before the page is sent, the server strips the things that are yours and not the customer's: material cost, your markup, your quantity buffers, your labour rates and how they were worked out, and every saved draft and earlier version. The customer's browser receives the sell prices it needs to add up their own choices, and nothing behind them.
- The decision expires. Accepting or declining stops working 90 days after you sent it. The page stays readable after that — a customer re-reading what they agreed to is a good thing — but nobody can accept a price you set three years ago.
- You can end it. Withdraw the quote or close the account and the link stops answering.
- It is rate-limited, so the link cannot be used to hammer the server.
Signing in
Hashed passwords, signed sessions that expire — and no MFA yet.
- Passwords are hashed by Supabase Auth. Nobody at RoofMap can see one, including us.
- A session is a signed token that expires and is re-checked on every single request. It carries a version number, so changing a password invalidates sessions already issued — if a device goes missing, a password reset logs it out.
- Sign-in is rate-limited twice over: by where the attempt comes from, and by the email address being tried. Guessing one account's password at scale is not a thing you can do from the outside.
- Registration, password resets and email verification are each rate-limited separately, and a reset link is short-lived.
There is no multi-factor sign-in today. If someone has a user's password, they have that user's RoofMap. That is the gap we would most like to close, and saying so is more use to you than a paragraph that talks around it.
What sits on a phone on site
A working copy so the app survives no signal — protected by the phone, not by us.
RoofMap keeps working on a roof with no coverage, which means the job you are on is held in the browser's own storage on that device until it syncs. That copy includes the drawing, the measurements and any photos you have taken, plus your sign-in token and your layout preferences. Once the work reaches our servers the local copy is deleted.
RoofMap does not add its own layer of encryption on top of that. It relies on the device's own disk encryption and lock screen — which on any current iPhone or Android is on by default and is genuinely strong, but is the phone's protection rather than ours. This is the same position as every other browser-based field tool, and we would rather you knew it than assume we had done something extra.
What follows from that is practical: put a PIN or biometric lock on any device that opens RoofMap, and sign out on a shared or borrowed one — signing out clears the local copy.
Keeping one business out of another's
Every query is filtered by the business that asked, and a test tries to break it.
Every job, drawing, photo, quote, price book and setting belongs to exactly one business. Every read and every write the server makes is filtered by that business before it reaches the database, so there is no screen and no API call that can return another company's rows.
Saying that is easy, so it is tested rather than asserted. One suite signs in as one business and tries to reach another's job, quote and backup by putting their ids in the URL — the way a real attempt would look — and the build fails if any of it comes back. Another feeds a job full of customer names, addresses and prices through every one of the admin screens we use to run the service, and fails if a single field of it appears: those screens show accounts, not anybody's work.
RoofMap is built and run by a working roofer, and that deserves a straight answer rather than a reassuring one. The founder's own roofing business holds an ordinary account with exactly the same walls around it as yours. The full version of that answer — including what one or two people can reach in order to keep the service running, which is not nothing — is in the privacy policy.
Your price book
The question roofers ask first, answered one worry at a time.
Your rates are the most sensitive thing you will put into RoofMap — more than the jobs, more than the customers. You are typing them into software owned by another roofing company, and the only answer worth anything is a specific one. So here is each worry on its own.
"Can you see my rates?"
Not through RoofMap. Your price book belongs to one business, and every read and every write is filtered to the business that asked before it reaches the database, exactly as described above. The admin screens we use to run the service show accounts — business name, plan, how many people, whether the trial has run out. There is no screen that shows a price.
That is tested rather than promised. One suite builds a company whose job carries a deliberately odd material rate and a note about a thin margin, pushes it through every one of those admin screens, and fails the build if either string comes back out. The day somebody adds a "just show me their price book" screen to chase a bug, the build stops.
What is also true, and we will not dress it up: one or two people at RoofMap can reach the database itself, because somebody has to be able to restore a backup or fix a save that broke. That access exists to run RoofMap and for nothing else, we do not look at a subscriber's prices, and the longer version of that answer is in the privacy policy. If what you need is a technical impossibility, no company of this size can honestly sell you one — including this one.
"Will it be used to work out what anyone else charges?"
No. Your rates are never shown to another subscriber, never sent to a supplier, and never pooled into an average, a benchmark or a "typical price in your region". RoofMap ships default prices taken from published retail figures, the same for everybody, and they sit there until you type your own over them. Nothing in the software reads your book to price somebody else's job, and nothing will without asking you first.
"Can my own customer see my margin?"
No — and this one is worth describing, because it is how a margin leaks quietly. The customer's quote page used to be handed the whole quote so it could work out option prices in the browser, which meant the cost basis sat in that page's data for anyone who opened the browser's developer tools. The office prices the options before sending now and the page only adds up sell prices: material cost, the mark-up percentages, the scaffold cost and your labour cost rates never leave the office. A test sends a quote carrying all four and fails the build if any of them turns up in the customer's copy.
"What happens to the price list file I upload?"
A supplier CSV or PDF is read in your own browser. It goes to an AI service in exactly one case — you pressing Read it with AI on a PDF that could not be read on its own — and then it is the file's text, to Anthropic's Claude, which does not use data submitted through its API to train models. Nothing about your price book is ever sent for AI in the background. The number of places in the app that can make that call is counted by a test, so a third one cannot be added quietly.
"Can I get it back out again?"
Yes, and check it on day one rather than taking our word for it: Settings → Pricing → Custom Price Book → Download as CSV gives you your own list back, whenever you like, without asking us. Your book is also versioned — previous copies are kept and any of them can be restored — so an upload that lands on the wrong thing is a nuisance rather than a disaster.
"So what actually guards it?"
Your password, today. There is no multi-factor sign-in yet, and on a page about your price book that is the sentence that matters most: it is in the gaps list, it is the gap we care most about closing, and until it is closed the honest advice is a password you use nowhere else. Inside your own business, everyone you invite can see the price book — there is no way yet to let a crew member use the job pack without seeing your rates.
The Fergus connection
Your own key, used only for you, and you can kill it from the Fergus end.
This is not an OAuth integration and we do not describe it as one. Each company pastes in its own Fergus personal API key. There is no shared RoofMap key and no fallback: if your key is not there, nothing of yours talks to Fergus.
- The key is used server-side only, for your company's own requests. It is never sent to a browser other than back into the settings screen you typed it into.
- Revoking it in Fergus kills it immediately — you do not need us to act, and you do not have to tell us.
- Clearing the field in RoofMap settings means we stop holding it at all.
- When you run the built-in connection diagnostic, the report it produces records the key's length and never the key. A test fails the build if that ever changes.
The same shape applies to any job-system key: it is yours, it is per-company, and you can end it from the other end without asking us.
The team inbox
Mail passwords encrypted with AES-256-GCM, and never handed back out.
The Business plan can pull your real email into RoofMap, which means we hold a credential for a mailbox. That is the most sensitive thing in the system and it is treated that way.
- The password is encrypted at rest with AES-256-GCM under a key held only in the server's environment — not in the database, so a copy of the database is not enough to read it.
- It is never returned by any API response. Not to the admin screens, not to support, and not to the account that entered it. Once it goes in, the only thing that can use it is the server making a mail connection.
- Incoming HTML is sanitised on the server before it is stored — scripts, event handlers and
javascript:links are removed — and then rendered inside a sandboxed frame. Remote images are held back until you ask for them, so simply opening a message does not tell the sender you read it.
Where it runs
Managed infrastructure, outside New Zealand, encrypted in transit.
| Who | What it does | What it holds |
|---|---|---|
| SupabaseDatabase & sign-in | Stores the data and handles passwords. | All of it, encrypted at rest by the provider. |
| RailwayBackend hosting | Runs the server the app talks to. | Everything, in transit. Server logs. |
| VercelWebsite hosting | Serves the app and the customer quote pages. | Request logs and IP addresses. No job data is stored there. |
All three run outside New Zealand, and there is no NZ-resident option today. Traffic between your browser and our servers, and between our servers and every provider, is encrypted with HTTPS/TLS, with HSTS set so a browser will not fall back to an unencrypted connection. The API refuses to be framed by another site, and the pages set the headers that stop content-type guessing and limit what is leaked in a referrer.
The full list of every company your data passes through, what each one gets and how long anything is kept is in the privacy policy, and it is checked against the code — a new outbound call to a third party fails the build until that page names it.
What we have not done yet
The list every security page should have and almost none do.
RoofMap is built by a small team inside a roofing company. Some things are not built yet, and you are better served by a list than by silence.
- No multi-factor sign-in. Password only, today. This is the one we care most about closing.
- No way to hide prices from your own staff. Everyone you invite into your business sees the same price book and the same margins. A crew member who only needs the job pack on site still sees your rates.
- No New Zealand data residency. Your data goes offshore. If that is a dealbreaker for your business, it is a dealbreaker — better to know before you start than after.
- No RoofMap-level encryption of the on-device copy. It leans on the phone's own encryption and lock screen, as described above.
- No formal certification. We hold no ISO 27001 or SOC 2 report. What we have instead is a test suite that runs on every single deployment and a policy of writing down what is actually true, which is not the same thing and we are not going to pretend it is.
If one of these is blocking you, say so — knowing which of them a real roofing business actually stops at is how we decide what to build next.
Reporting a problem
Tell us and we will fix it. No lawyers, no runaround.
If you think you have found a security problem in RoofMap, email support@roofmap.co.nz with enough detail to reproduce it. We would far rather hear it from you than from a customer.
- We will acknowledge it, and we will tell you what we found and what we did.
- We will not threaten anyone who reports something in good faith.
- Please do not test against another business's live data. If you need an account to poke at, ask and we will give you one.
If there is ever a breach likely to cause serious harm, we will notify the people affected and the Office of the Privacy Commissioner, as the Privacy Act 2020 requires. That commitment is in the privacy policy too.