Trust and security

Built like the infrastructure it claims to be.

Customer messages are the most sensitive data most businesses hold. Here is how they are handled, stated precisely, with nothing on this page that is not already true.

The controls

Eight, and each one is a decision written down somewhere rather than an aspiration. Where a control has a test behind it, the test is what makes it a control.

EU hosting, one jurisdiction

The database and the API both run in Frankfurt, Germany. Not a region you pick per workspace — a single jurisdiction for everything, which is the part that makes the answer to "where is my data?" short.

Encryption at rest

AES-256-GCM envelope encryption. Every secret row carries its own key, wrapped by a master key that lives only in the environment, and the wrapping is bound to the row it belongs to — so a ciphertext copied to another row fails to decrypt rather than quietly working.

Tenant isolation at the database

Row-level security on every table, and the application connects as a role that cannot bypass it. Application-level filtering is belt and braces here; it is never the mechanism. A test asserts that no table carrying an organization column lacks a policy.

Signed webhooks, both directions

Inbound events are signature-verified against the raw body before anything parses them, in constant time; a failure is discarded unparsed. Outbound deliveries are signed with a timestamped HMAC — Stripe’s scheme, deliberately, because every language already has a snippet for it.

SSRF containment

One outbound HTTP client, and no module may construct its own. Customer webhook destinations are re-resolved and re-checked on every delivery, not only at registration — so a hostname that was public when you added it cannot later point inward.

No message content in error tracking

Structural redaction rather than a regex over log lines: secrets are carried in a wrapper whose every serialisation returns a placeholder, and unwrapping it is reachable from two files. Our error tracker receives metadata and identifiers and never a message body.

Backups we hold ourselves

Point-in-time recovery at the database provider, plus our own nightly encrypted dump to storage we control — because "the vendor has backups" is not a recovery plan anybody has tested. Restore drills are scheduled and the measured time is written down.

AI providers see nothing unless you turn AI on

A business using Cosend for routing, the API and the inbox has no AI sub-processor at all. That is a property of where the calls are made from rather than a setting we promise to honour, and the sub-processor list says which providers are involved when you do enable it.

Retention and deletion

By default we store message content, because that is what makes the shared inbox, the history import, the AI context and the automation triggers possible. Two things bound it.

Your plan sets the retention default, and it is a ceiling rather than a starting point. You can configure retention down — never up — and the settings screen shows the longer options as disabled with the plan named, because a disabled option that says why is useful and a missing one is confusing. The ladder has each plan's figure.

Or store nothing at all. Direct-delivery mode verifies the inbound webhook, records metadata only — timestamp, direction, message ID, contact hash, type, status — forwards the full payload to your endpoint and never writes the body. It is a per-connection setting and it is free on every plan. You give up the inbox, the history import, AI and content-based triggers, and the dashboard disables those features for that connection rather than failing at runtime. How the three modes differ.

Deletion is deletion of the row and of the stored file, run by a scheduled sweep per organization and per data class. It is not a flag that hides a record from a query.

Availability

The target is 99.5%, and it stays 99.5% until the architecture changes. A higher figure would look better on this page. It would also be an availability we have not built — the database and the API are both managed services we do not control, which is the trade we made for having no servers to administer, and it is stated here rather than hidden.

A published target we miss is worse than a modest one we beat. When the architecture justifies a higher number, the number moves; not before. Where status is reported.

What this page does not claim

No certification, and no badge implying one. We hold no third-party audit report and there is no audit under way, so there is nothing to put here — and a security page that implies otherwise is the exact document a buyer checks first.

No uptime figure we have not measured. The target above is a target. The moment there is a monitored history, it is published as history.

No claim that inbound events bypass us. By default they do not — we terminate the webhook and keep the record, and that is what makes the product work. The option to store nothing exists and is above; the claim that we never hold your payloads would be false for most connections.

A security questionnaire, or a vulnerability to report? security@cosend.app. We do not run a bounty programme and we do not ask for a disclosure embargo. The sub-processor list and the Data Processing Addendum answer most of what a questionnaire asks before you send one.