Security
Your studio's member list, payment history and phone numbers live in here. This page says exactly how they are protected, and, at the bottom, exactly what we have not done yet.
Isolation in the database
Every row carries a studio_id and Postgres Row Level Security enforces it, so a bug in ordinary request-handling code does not leak across studios. The honest caveat: background jobs and webhooks run with a service-role key that is designed to bypass RLS, so on those paths the isolation is our code, not the database. Those paths are the ones we review hardest.
No card data here
Card numbers go straight to Stripe from the browser and are exchanged for a token. Our servers never receive one, so a card number is not among the things an attacker would find here.
Identity we did not write ourselves
Staff sign in through Clerk. Members get a short-lived signed link. We store no passwords.
The one that matters most
Tenant isolation
Multi-tenant software has one failure mode that ends a company: one customer seeing another customer's data. Here is the specific way we make that hard.
Every table carries a studio_id. Members, bookings, classes, payments, kiln pieces, messages, notes. There is no shared table where records from two studios sit together without a tenant column to tell them apart.
Postgres Row Level Security enforces it, not the application. RLS policies live on the tables themselves. A query that forgets its studio filter does not return somebody else's rows; it returns nothing. This is the important part. Application-layer checks are one forgotten WHERE clause away from a breach, and every multi-tenant leak you have read about was one. Putting the boundary in the database means a mistake in an ordinary route handler usually surfaces as an empty page rather than as somebody else's data. The caveat we owe you: background jobs and webhooks run on a service-role key that is designed to bypass RLS, so on those paths the boundary is our code again.
The studio identity comes from the session, never from the request. Which studio a request may touch is resolved server-side from the authenticated Clerk organization. It is never read from a URL parameter, a query string, a client-supplied header or a request body. Changing the studio slug in the address bar to one you do not belong to gets you a denial, because the slug is not what grants the access, the session is.
Automated tests hold the line. The test suite asserts that staff routes go through the shared access check rather than rolling their own, so a new route that skips authorization fails CI instead of shipping.
Encryption
Everything moves over TLS. The marketing site, the app, the API and the webhook endpoints all refuse plain HTTP, and HSTS is set so a browser will not try it a second time.
Data at rest is encrypted by Supabase on AWS infrastructure using AES-256 with provider-managed keys, which covers the database volumes, the automated backups and any uploaded files. Secrets held in environment configuration are encrypted at rest by Vercel.
Authentication and access control
Staff sign in through Clerk. We never see or store a password, and we did not write the session handling ourselves, which is the right call for something this easy to get subtly wrong. Multi-factor authentication is available and we recommend turning it on for every owner account.
Each studio is a Clerk organization, and staff hold one of three roles inside it. An Owner can do everything, including billing and deleting the studio. An Assistant runs the day to day, takes bookings and handles members but does not touch billing. An Instructor sees their own classes and rosters and little else. Roles are checked server side on every request, not hidden in the interface.
Members do not get a password, because a password is one more thing for them to reuse and lose. They get a magic link containing a signed, short-lived token scoped to that one member and that one studio. It expires, and an expired or tampered token is refused.
Kiosk check-in runs on its own scoped, time-limited token so a tablet left on the counter cannot be used to reach the admin side of the account.
Secrets management
API keys, signing secrets and database credentials live in encrypted environment configuration, injected at runtime. None of them are committed to the repository, and the repository is scanned for accidentally committed secrets.
Server-only secrets are kept out of anything the browser receives. Third-party credentials are held per studio where the integration allows it, so one studio's Twilio or Stripe connection is not usable by another. If a secret is exposed we rotate it rather than assess whether it was probably fine.
Payment isolation
Card numbers never reach BookClay servers. Payment fields are rendered by Stripe inside their own iframe, the card goes directly from the customer's browser to Stripe, and what comes back to us is a token, a brand and the last four digits. We could not leak a card number, because we never receive one.
Money is handled the same way. Class fees and membership dues are charged on the studio's own Stripe account using Stripe Connect direct charges, and settle from Stripe to the studio's bank. BookClay is not a money custodian, is not a payment processor, and never holds studio funds. There is no balance here to lose, freeze or misapply.
Webhook verification
Anything that arrives claiming to be an event from another service is verified before a single line of it is trusted. An unverified webhook is an unauthenticated write endpoint, which is a good way to have someone mark invoices paid for free.
- Stripe events are checked against the endpoint signing secret with Stripe's own constructor, against the raw request body, so a replayed or edited payload fails.
- Clerk events are verified with Svix using the signing secret and the svix-id, svix-timestamp and svix-signature headers. A missing header is a rejection, not a warning.
- Twilio requests, including inbound SMS to the AI front desk, are validated against the X-Twilio-Signature header using the studio's auth token before the message is processed.
Handlers are written to be idempotent, so a duplicate delivery does not double-charge or double-send.
Monitoring and logging
Sentry captures errors and performance data across the browser, the server and edge runtimes, with the studio and user identifier attached so we can tell whose problem to fix. It usually means we know something broke before you email us about it.
Application logs are structured and kept for 90 days. We deliberately keep sensitive values out of them, and stack traces are scrubbed of secrets before they leave the process.
Backups and recovery
The database is backed up automatically with point-in-time recovery across a rolling 30-day window, and backups are encrypted with the same key management as the live data.
Separately from our backups, you can export your own members, bookings, payments and kiln records to CSV at any time from inside the app. That matters more than our restore procedure does, because it means you are never waiting on us to have a copy of your own studio.
No badges here
What we don't have yet
Every security page on the internet lists the good parts. Here are the gaps, because you will find them during procurement anyway and it is better you hear it from us.
No SOC 2 report
We have not been through a SOC 2 Type I or Type II audit. If your insurer or your board needs one, we do not have it, and we are not going to imply otherwise with a badge.
No third-party penetration test
The application has had an internal security review, and the findings from it are tracked and worked. It has not been tested by an outside firm.
No bug bounty
There is no paid program and no formal safe-harbor policy document. We will still thank you properly, credit you if you want, and fix what you find.
No contractual uptime SLA
We watch availability closely and it has been good, but we do not yet publish a number with credits behind it.
No customer-managed encryption keys
Encryption at rest uses the provider-managed keys described above. Bringing your own key is not supported.
BookClay is early and small. The architecture above is genuinely solid, and the compliance paperwork that proves it to a third party is not written yet. Those are two different things and we are not going to blur them.
Responsible disclosure
Reporting a vulnerability
If you have found something, please tell us before you tell anyone else. Email security@bookclay.app.
We aim to acknowledge your report within two business days. That is a commitment we intend to keep rather than a contractual SLA, because this page is honest elsewhere about not having one. We will tell you what we think of it once we have looked, keep you updated while we fix it, and credit you publicly if you want the credit.
Useful things to include, if you have them:
- what you did, in enough detail that we can reproduce it;
- what you saw, and what you expected instead;
- the impact as you see it;
- any account or studio you were signed in as at the time.
Please test only against your own account or a demo studio, do not access, alter or exfiltrate anyone else's data, do not run denial-of-service or spam testing, and give us a reasonable window to fix it before publishing. Do that and we will treat your research as authorized and welcome, not as a violation of our terms.
There is no bounty program. There is a person who reads that inbox and will actually fix what you send.