Compliance
You are the data controller; the processor runs in your environment.
This page covers the GDPR / SOC 2 controls the system ships — the data it stores, the data-subject-request endpoints, retention, and audit trails. It pairs with Security and Data boundary, which own the access and privacy mechanics.
The controller/processor model, the shared-responsibility split, and Anyray's regulatory standing are on the Anyray compliance page. This page documents the shipped controls.
Anyray holds an independent SOC 2 Type I attestation of its own program (as of 6 July 2026), examined by Securance Pro Assurance PLLC against the Security, Availability, and Confidentiality Trust Services Criteria. A SOC 2 Type II examination is in progress. The report is available under NDA — contact security@anyray.ai. Because Anyray is self-hosted, the attestation program for your deployment stays yours; Anyray supplies the control inventory and audit evidence to support it.
What data your deployment stores
Every store below lives on your volumes — none on a vendor system. The one exception is the Billing app account plane (last two rows), which carries content-free metadata only (counts, aggregates, pseudonymous seat hashes), never prompt/response content.
| Store | Data | Where |
|---|---|---|
| Spend store | Per-request metadata: user/team, model, provider, tokens, cost, latency. Never content. | Your Postgres (anyray_spend) |
| Connector observations (when configured) | Official vendor usage metadata: timestamps, user/model identifiers, vendor-native quantities, and reported cost. Never prompts, responses, source code, or attachments. Kept separate from request spend. | Your Postgres (anyray_spend_connector_events) |
| Observability traces | Attribution + token/cost/latency metadata; content only per the content mode (ciphertext in encrypted, none in off, raw only in deploy-gated plaintext). | Your Postgres (anyray_traces / anyray_observations) |
| Client keys & enrollment links | Usernames bound to records — token hashes only (SHA-256), never raw values. | Gateway data volume |
| Optimizer ephemeral stores | Semantic-cache responses and stashed originals, in memory, TTL-bounded, keyed by content-free hashes. | Optimizer memory |
| Audit logs | Admin/GDPR actions: actor + action + timestamp. Metadata only. | Your Postgres (anyray_audit_log); per-pod files as fallback |
| Anyray Billing app plane | Operator emails/names (Google sign-in), tenant memberships, content-free usage rollups, seat hashes, and the deployment heartbeat (health, counts, error class names, env-var names — never values, content, or user identities). | Vendor Billing backend |
| Support bundles (explicitly pushed) | Only when an admin clicks Send: the redacted, content-free diagnostic bundle plus its analysis. Never automatic, never pullable by Anyray. | Vendor Billing backend (newest 20, 90-day retention) |
Seat identifiers sent to the Billing app are HMAC-SHA256'd with ANYRAY_PSEUDONYM_SALT, which never leaves your environment — so they're re-identifiable only with a salt the vendor never holds. Set the salt: unset, the gateway falls back to an empty-key HMAC, making the digests dictionary-checkable. Drop service/bot accounts before pseudonymization with ANYRAY_SEAT_EXCLUDE.
Content at rest is AES-256-GCM, keyed by ANYRAY_CONTENT_KEY (see Encryption at rest). There is no keyring: set a new key and blobs written under the old one become permanently undecryptable unless you re-encrypt them offline first. Store the key in your secret manager, not the repo.
Data subject requests
The gateway exposes admin-gated endpoints for erasure and export. All are capability-gated under RBAC (security_admin or owner; the break-glass ANYRAY_ADMIN_TOKEN always works), and each call is itself audit-logged.
Erasure (GDPR Art. 17)
| Store | Endpoint | Removes |
|---|---|---|
| Gateway | delete /admin/gdpr/users/:user | Every spend row, cap counter, client key, and enrollment link for the user (which also cuts their access), plus their trace rows. An owner-level request also removes connector observations whose exact attribution.user or userId matches. Returns per-store counts. |
| Optimizer | post /admin/optimizer/purge | Drops the whole semantic cache and stash from memory. |
| Anyray Billing app | delete /portal/me | A portal operator self-erases their account, memberships, and sessions. Refuses (409) if they're a tenant's sole owner. |
Its stores are keyed by content-free hashes with no per-user index, so one user can't be selectively purged — the call clears everything (entries expire on their own within an hour anyway).
Access & portability (GDPR Art. 20)
| Scope | Endpoint | Returns |
|---|---|---|
| Gateway | get /admin/gdpr/users/:user/export | Everything the gateway holds for the user as JSON — spend rows and, for an owner-level request, matching connector observations (all metadata only; content stripped defensively even in plaintext) plus key/link metadata (hashes stripped). |
| Anyray Billing app | get /portal/me/export | A portal operator's own account data: profile, memberships, and audit-log entries. |
Tenant SSO users cannot export or delete connector rows. Only the deployment owner or
ANYRAY_ADMIN_TOKEN can. This prevents cross-tenant access.
Retention (GDPR Art. 5(1)(e))
Storage limitation is per-store. Only the spend/trace window is a knob you set directly.
| Store | Default | Configurable? |
|---|---|---|
| Spend store | Unset = kept indefinitely (ANYRAY_SPEND_RETENTION_DAYS prunes at boot and daily) | Yes |
| Connector observations | 90 days maximum; a shorter positive ANYRAY_SPEND_RETENTION_DAYS applies. Cleanup continues without active connectors. | No |
| Observability traces | 90 days (overridden by ANYRAY_SPEND_RETENTION_DAYS when set) | Yes |
| Optimizer cache / stash | In-memory, lost on restart (cache 3600s, stash 1800s); durable stash rows swept hourly | No |
| Optimizer decision pins | Pruned after 30d idle | No |
| Audit logs | Kept indefinitely in Postgres (unpruned by spend retention); fallback files until rotated | Via your Postgres retention |
| Billing app plane | Sessions expire; invites pruned after 90d; usage rollups tiered (30d / 90d / 365d) | ANYRAY_CP_RETENTION_TIERS |
| Support bundles (vendor side) | Newest 20 per deployment, 90d | No |
Audit trails (SOC 2 CC6/CC7)
Every admin mutation is recorded as an append-only, metadata-only event ({ ts, actor, action, category } — never content). The actor is the SSO operator's IdP email, or break-glass for anything done with the shared admin key. Trails are written to the shared spend Postgres (anyray_audit_log), so they're durable across restarts and centralized across replicas; per-pod files under ANYRAY_DATA_DIR are the dev fallback and outlive spend rows (compliance evidence).
Covered domains include GDPR/DSAR operations, content-mode changes, client- and provider-key and enrollment-link changes, user caps, routing and model aliases, optimizer config and purges, admin sessions, and the Billing app lifecycle. The access controls behind these trails — admin-token auth, console SSO with RBAC, the auth-failure throttle, and signed sessions — live in Security.