Trust
Security
What actually protects your customers' data, described specifically enough to be checked.
Last updated August 19, 2026
The short version
Dealership isolation is enforced by the database, not by our queries. A query that forgets to filter by store returns nothing — not another dealership’s customers.
Every page is private unless it is explicitly listed as public, so a new screen is protected the day it is written rather than the day someone remembers.
Customer documents live in a private bucket and are only ever read through links that expire in ten minutes.
We hold no security certifications. We describe the controls instead, and we say which ones we do not have.
Tenancy isolation
A dealer group’s data being visible to another dealership is the failure that would end this company, so it is enforced at the lowest layer available rather than in application code.
- Row-level security is FORCED on every table, with policies keyed to the signed-in user’s identity.
- Every request made on behalf of a person runs inside a transaction that drops to a restricted database role and carries that person’s identity as a claim the policies read. The consequence is the one that matters: a query that forgets its store filter returns zero rows, rather than someone else’s.
- The code paths that must run privileged — establishing who you are, the overnight jobs, billing operations, accepting an invitation before you have a role — are enumerated in the repository by category, each with a written reason it cannot run inside the fence.
- Both directions of the isolation are tested against a real Postgres: that a policy without a grant fails loudly, and that a grant without a policy silently writes nothing.
- The migration tool that would drop these policies is deliberately sabotaged in this repository so it cannot be run by accident.
Authentication and access
Deny by default
Route protection is an explicit allowlist. Anything not named as public requires a signed-in user, so adding a page protects it automatically. The list is small, unit-tested, and every entry on it carries a written reason.
Sessions
Authentication is handled by Supabase. The session lives in httpOnly cookies that page scripts cannot read — set that way explicitly, not left to a library default — is refreshed server-side as you use the product, and is cleared by signing out.
Roles
A person’s role comes from the dealership membership they actually hold, resolved server-side on every request. Which rooftop they are working is a browser-side preference, and it is only ever used to choose from the stores their account provably has a role at — never to look one up. Pasting another dealership’s identifier into the browser resolves to nothing.
Scheduled jobs and webhooks
The overnight jobs authenticate a shared secret and refuse every request outright when that secret is not configured, rather than falling open. Payment webhooks are verified against Stripe’s signature, and an unset signing secret refuses every delivery rather than accepting unverified JSON.
Bearer credentials
Three things in the product are opened by a link or a code rather than a password: a staff invitation, a service menu sent to a customer’s phone, and a paired customer tablet. The credential each one ultimately rests on is built the same way.
- 32 random bytes from the operating system’s cryptographic source.
- SHA-256 stored; the raw value never written down. A copy of our database does not yield a working link. Lookups compare hashes.
- Scoped to one store and one purpose, and expiring where expiry makes sense — a customer menu link dies in twelve hours. A paired tablet’s token is deliberately long-lived; revoking the pairing is how it ends.
- Comparisons that could leak information through timing use constant-time comparison.
The six-character code a tablet pairing starts from is not one of these credentials. It is a claim ticket: it lives for ten minutes, is exchanged exactly once for the 32-byte token above, and is deleted the moment that exchange succeeds — which is what lets it be short enough to type.
Customer documents
An uploaded service contract is the most sensitive object in the system: it carries a customer’s name, their VIN, and often their signature.
- Stored in a private bucket. The provisioning script refuses to leave the bucket public and says why.
- Read back only through signed URLs that expire in ten minutes, generated per request. There is no permanent public address for any customer document.
- Accepted file types are restricted at the bucket, not only in the browser.
Audit log
Actions that matter — confirming a contract, changing a subscription, granting a role — are recorded with the actor, the record, and what changed.
- Append-only. There is no update or delete policy on the audit table, deliberately, and the product contains no code path that edits an entry. A log anyone can edit is not evidence.
- Credentials are redacted before writing. Anything whose field name looks like a token, password, secret, API key, authorization header, cookie or SSN is replaced with a marker — matched case- and separator-insensitively, at any depth, and marked as redacted rather than silently dropped so it is visible that something was there.
- Readable for the dealerships you belong to, under the same row-level policies — and by our platform-support role, which is stated here because “only” would have been doing dishonest work.
AI data handling
One model, one vendor, two features: reading an uploaded service contract, and the in-product Co-Pilot.
- Anthropic’s commercial API terms state that data submitted through the API is not used to train their models. We do not train models on customer data either.
- Extracted fields are never trusted. They are stored as machine-read and unverified, the coverage engine downgrades its confidence because of it, and nothing reaches a coverage answer until a person has confirmed each field against the document in their hand.
- Where no AI provider is configured, the product says so and refuses to proceed rather than inventing plausible values.
The full mechanism, including what the advisor’s confirmation does and deliberately does not mean, is on the Responsible AI page.
Infrastructure and encryption
DealerTech.io runs on four vendors. Each is named because a subprocessor list this short is worth publishing. One more external service receives data from the product: NHTSA’s public APIs, which are sent a VIN to decode it and a make, model and year to look up recall campaigns — and nothing about the customer. A government data source rather than a vendor, but a complete list is only worth having if it is complete.
Supabase
Postgres database, authentication, and the private bucket customer documents are stored in. This is where dealership data lives.
Stripe
Subscription billing. Stripe holds the card; we never receive or store card numbers.
Anthropic
The model that reads uploaded service contracts and answers Co-Pilot questions. API data is not used to train models.
Netlify
Hosting and the scheduled jobs that run overnight.
Traffic is served over HTTPS only. Data at rest is encrypted by our hosting providers, whose own documentation and compliance reports are the authority on the specifics — we point at theirs rather than restating figures we do not operate. No card data ever reaches our application; card entry happens on Stripe’s hosted pages.
Application secrets are held as environment variables in the hosting platform, never committed to the repository. The repository itself is private.
How we build
- TypeScript in strict mode. The decision-making engines — coverage, pricing, prep sheets, scheduling, billing — are pure functions with no I/O, so their behaviour is provable in tests rather than inferable from a running system.
- Roughly 1,400 unit tests. Security seams have tests that exist specifically to fail if the seam moves: route protection, tenancy isolation against a real database, the whitelist that decides what a customer’s tablet is allowed to receive.
- Customer-facing data is a whitelist, not a filter. Adding a field to an internal record does not add it to what a customer’s screen receives — somebody has to decide to send it, and a test asserts that the internal coaching fields never appear at any depth.
- The drive, customer and vehicle screens are served with headers instructing intermediaries and search engines not to cache or index them.
Reporting a vulnerability
Email info@dealertech.io with enough detail to reproduce it. We will acknowledge it, tell you what we find, and fix what needs fixing. We will not take legal action against anyone who reports a finding in good faith, gives us a reasonable chance to fix it before publishing, and does not access, alter or exfiltrate data belonging to a dealership or its customers while investigating.
There is no bug bounty. We are a small team and we would rather promise a real response than a payment we cannot underwrite. Machine-readable contact details are at /.well-known/security.txt.
What we do not have
DealerTech.io holds no security certifications. No SOC 1, no SOC 2, no ISO 27001, no ISO 27701, no ISO 42001. We do not have a compliance team, a formal penetration-testing programme, or a third-party auditor.
That is what being early looks like, and pretending otherwise on a page a dealer’s IT department will read is a lie with a paper trail. A SOC 2 audit becomes worth its cost when there are enough dealerships depending on us to justify it — a customer count, not a marketing decision — and we are not going to announce a timeline we have not committed to.
What we offer in the meantime is this page: the controls stated specifically, so your IT contact can evaluate them directly instead of trusting a logo. If they have questions this page does not answer, they can ask and get an answer from the person who wrote the code.
The rest of the compliance picture — the Safeguards Rule, TCPA, CCPA and the questions a vendor questionnaire asks — is on the compliance page.
This document was written from the software it describes, and has not been reviewed by counsel. It is the honest starting text, not legal advice. If a term here matters to your dealership’s decision, tell us and we will get it right rather than argue it later.