Security

Last reviewed: September 2026 · Report an issue: support@opbot.io

1. What this page is

OpBot holds a coach’s leads, their conversations and their calendar, and it sends messages under the coach’s name. This page says, in plain words, what protects that: what is built into the product, what our providers do, and what is not in place yet. It is our own description, not a certification. No third party has audited it. The contractual version of these measures is Annex 2 of our Data Processing Agreement, and section 17 of the Privacy Policy says what happens if personal data is ever breached.

2. Where your data lives

  • Hosting. The application runs on Vercel. The database is PostgreSQL, managed by Supabase on Amazon Web Services in the United States.
  • In transit. Every connection to OpBot uses TLS. A browser that has visited once is told to use HTTPS only, for two years and across subdomains, and the header carries the preload directive.
  • Cards. A card number is typed into Stripe’s own form and goes to Stripe directly. OpBot keeps a reference to the card, its brand and last four digits, never the number.
  • Providers. The services that process data for us, and what each one sees, are listed in section 11 of the Privacy Policy: Anthropic, Stripe, Supabase, Resend, Twilio, Vercel, Google, Zoom, Cloudflare, Upstash, Discord and Meta.

3. Keeping each business’s data separate

  • Row-level security on every table. A check in our build pipeline reads every table the database migrations have ever created and fails if one lacks it, so a new table cannot ship without it.
  • Entitlements only the server can change. The columns that decide what an account is entitled to, its plan, its credits, its founder and platform-owner flags and its billing links, are guarded by database triggers. A signed-in user’s own session cannot write them; only the server can.
  • Scoped access for agencies and teams. When the server acts for an agency on a client account, or for a team member inside a business, every query is scoped to that business in code, and a scanner in the build pipeline fails a server-side write that carries no business scope.
  • Roles. A team member sees only the tabs their role allows (coach, closer, setter, operator or admin), and an agency reaches a client account only through the agency’s own verified session.

4. Credentials and sensitive content

  • Connected accounts. The tokens for Zoom, Google Calendar and Meta, Twilio auth tokens, ESP and Calendly keys, Slack webhook URLs and pixel tokens are encrypted with AES-256-GCM before they are stored, under a key that exists only in the server environment. Call transcripts and their summaries are encrypted the same way. A health check confirms the active key still decrypts what it encrypted.
  • API keys. A key for the inbound API is stored only as a SHA-256 hash and shown once, at creation.
  • Links sent to leads. The booking, rescheduling and unsubscribe links we email are signed with HMAC-SHA256, and a booking link expires after two hours.
  • Passwords. OpBot does not store passwords. Sign-in is verified by Supabase Auth, which keeps only a salted hash.

5. Accounts and sign-in

  • Server-side sessions. Every request to the app is checked against the session on the server, not only in the browser.
  • Sign-in attempts are limited. Password sign-in is relayed through our server, which limits attempts per IP address and per email address before the credentials are checked.
  • Bots cannot sign up. Signup is protected by Cloudflare Turnstile, enforced by Supabase Auth itself so that it cannot be skipped by replaying the request.
  • Two-factor authentication. Any account can add a 6-digit code from an authenticator app under Settings → General. Once it is on, every sign-in asks for the code, and a session that arrives with the password alone is refused by the app and its API alike until the code is entered. It is required for the owners of agency plans, for team admins and for the platform’s own staff from October 5, 2026. No backup codes are issued yet: a lost authenticator is removed by support after an identity check, and section 4 of the Terms asks every account holder for a strong password used nowhere else.

6. Defences in the application

  • Headers. Every app page is served with a Content-Security-Policy, cannot be framed by another site, sends no referrer beyond the origin to other sites, and turns off camera, microphone and location access. Funnel pages carry a separate policy that permits a coach’s own tracking pixels and the embedded application form.
  • Cross-site requests. A request from a browser that changes something is refused when its Origin header does not match the site it was sent to.
  • Redirects. After sign-in, a visitor is only ever sent to a path on OpBot; a redirect target that points anywhere else is discarded.
  • Outbound webhooks. A webhook URL a coach configures is checked against private, link-local and cloud-metadata address ranges before anything is sent to it, the address is checked again when it is resolved, and redirects are not followed.
  • Funnel HTML. The HTML of a funnel page is sanitised on every render: scripts, inline event handlers and iframes from anywhere but the allowed video hosts are removed before the page is served.
  • Rate limits. Public forms, sign-in, checkout and the AI features are rate-limited, by IP address for visitors and by account for signed-in users.
  • Inbound webhooks. Every webhook we receive, from Stripe, Twilio, Resend, Zoom, Calendly, Meta and Discord, is verified against the sender’s signature before it is processed, and an event we have already handled is not processed twice.

7. Payments

Stripe processes every payment. OpBot’s own plans and credit purchases are charged through Stripe, and a coach’s product sales run through Stripe Connect on the coach’s own Stripe account, so a buyer’s card details and disputes sit with Stripe and the coach, never with OpBot. A payment changes an account only after Stripe’s webhook has been verified by signature and checked against the events already handled.

8. How changes reach production

  • Before a change merges it passes an automated test suite and a set of static checks, among them a scanner for server-side writes that carry no business scope, one for silently swallowed database errors, one for queries that would silently truncate their results, and one for links that break on a coach’s custom domain.
  • After every deploy a self-test exercises the live system end to end and reports to the team, including a probe that lists any database migration that was merged but never applied.
  • Errors are captured centrally and alert the team.

9. Deleting data

  • Cancelling deletes nothing. When a plan ends, the leads, funnels, sequences and history stay in the account, and resubscribing switches everything back on.
  • Closing an account is the separate, deliberate step that starts a 30-day clock. When it runs out, an automated job permanently deletes the account and everything under it, in small batches, re-checking every blocker before each deletion. A closure that cannot be verified is skipped rather than guessed at.
  • Leads are never swept. OpBot does not delete a coach’s leads on its own. A lead is removed only by the coach, at a lead’s own request through the coach, or by the closure above.

10. Reporting a vulnerability

If you have found a security issue in OpBot, we want to hear about it. Email support@opbot.io with Security in the subject line: the URL or feature affected, the steps to reproduce, and what you were able to see or do. The same contact is published at opbot.io/.well-known/security.txt.

  • In scope: opbot.io, the app, the funnel pages OpBot serves for coaches on any domain, and our APIs.
  • Out of scope: the services we build on (Stripe, Supabase, Vercel, Twilio, Resend, Cloudflare, Anthropic, Google, Zoom, Meta and Discord), which run their own programmes, and a coach’s own content, website or business.
  • Please: use only accounts you own; stop and report at the first evidence of a problem rather than exploring further; do not access, change or delete anyone else’s data beyond what is needed to show the issue; no denial of service, spam, phishing, social engineering or physical access; and give us reasonable time to fix the issue before you publish it.
  • What we promise: we acknowledge every report within five business days, keep you informed while we work on it, and will not take legal action against research done in good faith within these rules. We do not run a paid bounty programme today.

11. What is not in place yet

  • No SOC 2 report or ISO 27001 certificate. The DPA says what we provide in their place.
  • No independent penetration test has been carried out yet.
  • No backup codes for two-factor authentication yet; a lost authenticator goes through support (section 5).
  • No paid bounty programme.
  • No public status page. A personal data breach that affects you is communicated by email, as section 17 of the Privacy Policy says.

This page is reviewed when the product changes materially, and at least once a year.

12. Related documents