CAPITIS
Sign inCreate sandbox key

Security

Version 1.0 · Last updated 4 August 2026

This page is Annex II of the Data Processing Addendum — the technical and organisational measures we are contractually committed to. It describes what is in place today, and it ends with a list of what is not. We would rather you learned the gaps from us than found them yourself.

Reporting a vulnerability

Email security@capitis.app. Tell us what you found and how to reproduce it. We will acknowledge within 24 hours and keep you updated until it is closed.

Please do not run automated scanners against production, do not access or modify data that is not yours, and give us reasonable time to fix an issue before publishing it. We will not pursue legal action against anyone acting in good faith within those limits. We do not currently pay bug bounties.

How identifiers are protected

This is the part that matters most, so it comes first.

We never receive a raw identifier. Email addresses, phone numbers, card tokens, bank-link references and wallet addresses arrive as HMAC-SHA256 hashes computed on your side. There is no API field that accepts a raw email address for identity matching.

Hashes are hashed again before storage. A hash that reaches us is passed through a second HMAC using a server-side secret that exists only in the API environment — never in the database, never in the dashboard, never in a backup of the database. Stored identifiers carry a version prefix so the secret can be rotated.

Why that second step exists: the incoming hash is deterministic, which is what makes matching a returning shopper possible across publishers. Determinism cuts both ways — anyone holding both the hashing parameters and a guessed value could test whether it matches. Adding a secret the database does not contain means a stolen database, on its own, cannot be tested against a list of candidate email addresses.

These are pseudonymous personal data, not anonymous data, and we treat them that way in every policy on this site. Anyone who tells you hashed email addresses are anonymous is wrong.

Revocation is immediate. An identifier can be revoked individually through the dashboard or the API, which removes it from matching from that moment.

Infrastructure

  • All production infrastructure runs in Manchester, United Kingdom, on infrastructure operated by Hostinger International Limited.
  • End-user data — identifiers, clicks and conversions — is held in the UK and is never replicated to another country. Some customer contact data does leave the UK, because the services that send your sign-in emails and handle your billing sit outside it. Each one, and the safeguard covering the transfer, is named on the subprocessors page. None of them receives end-user data.
  • The database and cache are not reachable from the public internet. They listen only on the host's internal interface, and the host firewall denies all inbound traffic by default, permitting only administrative SSH and HTTPS.
  • Administrative access to the host is by SSH key only. Password authentication is disabled at the server, as is password-based root login.

Data in transit

  • TLS 1.2 or above on every public endpoint, with certificates renewed automatically.
  • HTTP Strict Transport Security is enforced (max-age=15552000; includeSubDomains), so browsers refuse to talk to us over plain HTTP after the first visit.
  • Additional response headers in force on every page: X-Frame-Options: DENY (no clickjacking via embedding), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, and a Permissions-Policy that switches off camera, microphone and geolocation.

Access control and tenant separation

  • Sign-in is by email link, Google or GitHub. There are no passwords for us to lose.
  • Session cookies are HttpOnly, Secure, SameSite=Lax, and use the __Host- and __Secure- prefixes, which stop a subdomain from writing them.
  • API keys are stored as hashes, never in plain text. A key is shown once, at creation.
  • Every API request is scoped to a single publisher. Every query filters by publisher at the application layer, so one customer's request cannot reach another customer's rows.
  • Internal endpoints used by the platform itself are separated from the public API surface and require their own credentials.
  • Administrative access to the dashboard is a separate, explicitly granted role.

Logging and audit

  • Structured application and access logging, with credential-shaped values redacted before they are written.
  • A per-publisher audit log records security-relevant actions — API key creation and revocation, identifier attachment and revocation, webhook changes — and is visible to you in the dashboard.
  • The click and conversion ledger is append-only in practice: records are written once and corrected by adding a later record, not by editing history. This is what lets a commission dispute be reconstructed months later.

Backups and resilience

  • The database is dumped nightly, compressed, and retained for 14 days.
  • Every dump is size-checked immediately after it is written, so a silent failure raises an error rather than leaving a directory of empty files.
  • Health and readiness checks run on every service; a watchdog restarts a service that stops answering.

Known gap — backups are on the same disk as the database. A nightly dump protects against a bad migration or a mistaken deletion. It does not protect against the loss of the host. An off-box copy is the single highest-priority item on our security roadmap. We are telling you this in the document that a court would read.

Software development

  • Every change goes through code review.
  • Continuous integration runs linting, type checking and the automated test suite on every change; a change that fails any of them does not merge.
  • Request and response bodies are validated against typed schemas at the API boundary, so malformed or unexpected input is rejected before it reaches business logic.
  • Database changes ship as reviewed, version-controlled migration files applied by a migration runner. Editing a production database by hand is prohibited by internal policy.
  • Secrets live in environment files on the host, never in the code repository. Documented handling rules forbid printing or logging them.

Incident response

If we discover a personal data breach affecting your data we will tell you without undue delay and in any event within 48 hours of becoming aware, with what we know at the time and the rest as we learn it. That commitment is contractual — DPA §7.

Security contact: security@capitis.app.

Business continuity and the honest bit

Capitis is an early-stage company operating a small, deliberately simple production estate. Some of what a mature vendor questionnaire asks for, we do not have yet. Here is the complete list, so you can make your own decision:

Not yet in placeWhat that means for youStatus
Off-box backupsLoss of the host would mean loss of recent dataHighest priority; in progress
Database-level row security policiesTenant separation is enforced by the application, correctly and on every query, but not additionally by the database itself. A bug in the application layer is not caught by a second layer.Planned as its own piece of work
Automated dependency vulnerability scanning in CIWe update dependencies, but no automated alert tells us the day a component we use is found vulnerablePlanned
SOC 2 / ISO 27001 certificationNo third party has audited these claimsNot started. We will not imply otherwise
Penetration test by an external firmNo independent adversarial test has been run against productionNot started
Formal disaster recovery testRestores have not been rehearsed end-to-end against a clean hostPlanned alongside off-box backups
Multi-factor authentication on customer accountsSign-in is passwordless — an email link or an identity provider. If you use Google or GitHub, whatever MFA you have there applies. If you use the email link, your inbox is the factorNative MFA planned
Encryption of data at rest on the host diskThe host's disk is not encrypted at the block level. Data at rest is protected by host access control and a firewall that denies everything inbound by default — not by disk encryption. Someone in physical possession of the underlying drive could read itPlanned
Encryption of stored network credentials with a dedicated keyThe schema is in place for it; today credentials rely on host access control rather than an application-layer keyPlanned
99.9% uptime commitmentWe do not offer a contractual service level yet, and we will not pretend toComes with general availability

If any of these is a blocker for you, say so at security@capitis.app. We would rather have the conversation than have you assume.


Security reports: security@capitis.app · Privacy: privacy@capitis.app

Single.id Limited, 20 Wenlock Road, London, England, N1 7GU — Company Number 17044105