Security · Compliance · Trust center
Security woven into every record.
Tenant isolation enforced at the database, not the application. Row-level access decided per record. Every read and write logged. AI agents inherit the same scope as the human they act for.
Compliance.
Where we are. What’s in progress. What’s projected. Nothing here is aspirational.
- In progressSOC 2 Type IISecurity & availability audit
Projected Q4 2026
- AuditedGDPREU data-subject rights
- PlannedISO 27001Information-security management
Projected 2027
- AuditedCCPACalifornia consumer rights
- PlannedHIPAAUS health-data handling
Projected 2027
In-progress and planned items are first-class. We don’t move them to “ready” until the auditor signs. Last reviewed Q1 2026.
Access decided per row. Not per app.
Every record carries a tenant, an owner, and a scope. One access function decides who can see what — and it runs whether the request comes from the UI, the API, or an AI agent’s tool call.
Five scopes evaluated per record.
- 5 access scopes: `org` · `team` · `managed` · `assigned` · `own`
- Scopes evaluated per record at query time
- Same logic in UI / API / agent tool
- Role-based permissions on top (e.g. `crm.contacts:read`)
- Custom roles per tenant
Every read, write, and access decision. Logged.
The audit log captures every action — by humans, by AI agents, and by system jobs. Filter by user, record, time, or rule. Export to CSV in one click. Retained per your tenant’s policy (default 90 days, up to seven years).
Audit log with mixed event types.
- Every CRUD action logged
- Per-agent tool invocation logged separately (three-lens)
- Access decisions logged with the rule that fired
- Retention policy per tenant (default 90 days, configurable up to 7 years)
- CSV export on demand
One invariant. Enforced everywhere.
Every database query from a user surface MUST pass through an access function. Our linter blocks any commit that bypasses it. The rule is the same for engineers, AI agents, and you.
Tenant isolation as an architecture invariant.
Most platforms enforce tenant scope in code paths. We enforce it as an architecture invariant. Every database query from a user-facing surface — every page render, every API call, every AI tool call — runs through an access function that is bound to your tenant. We can’t bypass it. Our linter blocks code that tries. Engineers can ship features; they can’t ship features that leak across tenants.
- F900 invariant in `CLAUDE.md` and code review
- `pnpm check:tenant-isolation` linter blocks unsafe calls
- System-context calls (jobs, hooks) require explicit `// system-context: <reason>` comment
- AI tools call `tenantWhere(ctx, ...)` before any DB query
- Tested via dedicated isolation tests in CI
Your data. Your region.
Pick a region when you create the tenant. Data and backups stay there. Cross-region access logs every time we touch your data from outside.
Tenant-level region pin.
- Regions: US (us-east-1) · EU (eu-west-1) · APAC (ap-southeast-1)
- Tenant-level region pin
- Backup co-located with region
- Sub-processor list per region
- Cross-region access logged
Retention. Breach response. Tenant erasure.
Three policies that run as code, not paragraphs in a contract.
- Retention: `retentionPruneJob` removes records older than your tenant’s policy. Configurable per collection.
- Breach notification: `notifyBreachJob` triggers on detected event; impacted tenants notified within SLA window. `DataBreachEvents` collection logs every incident.
- Tenant erasure: `eraseTenantJob` purges all tenant data on confirmed request — including backups within retention window.
- Access reviews: `accessReviewJob` produces quarterly review reports automatically.
- Password expiry: configurable per tenant (`passwordExpiryJob`).
For engineers
What an engineer sees on day one.
Read the access function, the linter rule, and the audit schema before your team’s vendor review meeting.
// Every user-context query passes both
const contacts = await payload.find({
collection: 'crm-contacts',
where: tenantWhere(ctx, additionalWhere),
user: ctx.user,
overrideAccess: false,
})
// System-context calls require justification
// system-context: scheduled retention prune
await payload.delete({
collection,
where,
overrideAccess: true,
})See compliance status, in full.
| Framework | Status | Audit firm | Next |
|---|---|---|---|
| SOC 2 Type II | In progress | Pending selection | Q4 2026 |
| GDPR | Ready | — | Ongoing |
| ISO 27001 | Planned | Pending selection | 2027 |
| CCPA | Ready | — | Ongoing |
| HIPAA | Planned | Pending selection | 2027 |
| Sub-processors | Published | — | Reviewed Q1 |
- SOC 2 Type IIIn progress
- Audit firm
- Pending selection
- Next
- Q4 2026
- GDPRReady
- Audit firm
- —
- Next
- Ongoing
- ISO 27001Planned
- Audit firm
- Pending selection
- Next
- 2027
- CCPAReady
- Audit firm
- —
- Next
- Ongoing
- HIPAAPlanned
- Audit firm
- Pending selection
- Next
- 2027
- Sub-processorsPublished
- Audit firm
- —
- Next
- Reviewed Q1
Need a SOC 2 report or a DPA?
Security review packages on request. SOC 2 reports under NDA. Custom DPAs for enterprise.