Security & compliance
PII handling, encryption, subprocessors, partner authentication, key revocation, kill-switch.
How we handle your data and your customers' data, what third parties touch it, and how to revoke access in a hurry.
Security contact: security@layers.com. PGP key available on request.
Commercial terms (signed DPA, custom retention, security questionnaires, audit reports) are negotiated at contract time. Contact legal@layers.com.
What data flows where
Three classes of data cross the network:
- Partner API traffic. The bytes you send to
api.layers.com/v1/*. Metadata (org, project, container ids) is logged with the request for 30 days; the body is not persisted beyond in-memory request scope. - Customer SDK events. Events your app emits via the Layers SDK to
in.layers.com. These carry the app-supplieduser_id, optionalemail, optionalphone, device identifiers, and the event properties you put on the payload. See PII handling at the SDK ingest below. - Generated + inbound social content. Video/image assets generated for your projects, plus public-post metadata pulled from connected social accounts and (for UGC) via SIFT.
PII handling at the SDK ingest
The SDK ingest endpoint at in.layers.com is the only customer-PII entry point. Before events are persisted, direct identifiers are normalized and SHA-256 hashed in process — plaintext email and phone are never written to storage.
| Field | Treatment |
|---|---|
email | Lower-cased, trimmed, SHA-256 hashed before persist + before CAPI forwarding. |
phone | Digits-only normalization, then SHA-256. |
user_id | Stored as-is. This is the id you assign — we recommend it not carry PII. |
app_user_id, revenuecat_original_app_user_id | Stored as-is. |
| IP address | Dropped at the edge after geo-IP region resolution. |
| Raw device identifiers (IDFA/GAID) | Forwarded to ad platforms only when you enable CAPI; not retained server-side past the forward. |
If your SDK integration sends emails with inconsistent casing or whitespace, the hash still matches because we normalize before hashing.
Compliance scope
- HIPAA — Not in scope. Layers does not process PHI. Partners must not transmit PHI via the API or the SDK.
- PCI DSS — Not in scope. Layers does not handle cardholder data; billing is delegated to Stripe.
- GDPR / CCPA — DPA available on request. See Data protection.
For security questionnaires, audit artifacts, or a signed DPA, email legal@layers.com.
Encryption
At rest. All primary-database data is encrypted at rest with AES-256. Column-level secrets (OAuth tokens, webhook signing secrets, CAPI access tokens) are additionally encrypted at rest with a column-level secret store — decryption requires the service role and happens at usage time in the background-processing tier, never in the partner API request path. Object storage for generated media uses provider-managed encryption keys.
In transit. TLS 1.2 or higher required everywhere. api.layers.com, in.layers.com, and docs.layers.com terminate TLS at a managed edge with managed certificates; HTTP traffic is redirected to HTTPS. Internal service-to-service traffic runs over private networking.
Subprocessors
We name every vendor that stores or processes partner or end-customer data. This list is kept current.
Material sub-processor changes ship via the Changelog. The commercial side of this — advance-notice windows, objection rights, contractual remedies — is governed by your DPA.
| Subprocessor | Purpose | Data touched |
|---|---|---|
| Google Cloud Platform | Application hosting, workflow orchestration, object storage | All application traffic, generated media, event stream |
| Supabase | Primary Postgres + auth + column-level secret store | Partner API state, customer event records (hashed PII), OAuth tokens |
| Upstash | Rate-limit + idempotency cache | API key ids, per-minute counters, idempotency body hashes |
| Sentry | Error tracking | Stack traces, request metadata (no bodies) |
| PostHog | Product analytics (internal) | Layers-employee product usage; no partner-visible data |
| Google Vertex AI / Gemini | LLM inference (content generation, scoring) | Campaign prompts, brand/profile text |
| OpenAI | LLM inference (select pipelines) | Same as above; per-request only, no training opt-in |
| Anthropic | LLM inference (select pipelines) | Same as above; per-request only |
| E2B | Sandboxed agent execution | Agent scratch space only; purged on sandbox close |
| Replicate | Model hosting (image/video model inference) | Generation inputs; per-request only |
| Stripe | Credit purchases + partner billing | Partner billing contact, invoice metadata |
| Resend | Transactional email | Partner recipient email; email body |
| Loops | Lifecycle email (Layers account-owner only) | Layers-employee email only |
| Cloudflare | Edge DNS + WAF on in.layers.com | Request metadata only; no bodies stored |
| SIFT (meetsift.com) | Public social-post metadata retrieval | Public post IDs, public metrics; no private account data |
Partner authentication
Partner API keys take the shape lp_<env>_<keyid>.<secret>. The secret portion is hashed with bcrypt at cost factor 12; only the hash is stored.
Verification is timing-safe: we use constant-time comparison so request timing can't leak whether a given key prefix exists.
Keys are never recoverable after issuance — we store only the bcrypt hash. If you lose a key, rotate it; we cannot send you the original.
Headers partners send
Authorization: Bearer lp_live_01HXZ9G7KMV2QX8Y1S5RJW3B7T.a4b3c2d1e0...See Authentication for the wire-level specifics.
Key revocation
Three ways a key stops working, in operational precedence order:
- Kill switch (
key.kill_switch = true). Immediate. Responses carry503 KILL_SWITCH. Used for runaway clients or emergency shutoffs. Reversible without re-issuing the key. See Rate limits → Kill switch. - Soft revoke (
is_active = falseorrevoked_atset). Permanent. Responses carry401 REVOKED. Used when a key is compromised, superseded, or the partnership ends. Not reversible — issue a fresh key. - Organization-level kill (
kill_switch.scope = "organization"). All keys for the org fail with503 KILL_SWITCH. Contractual remedy only.
Self-serve revocation
POST /v1/api-keys/:keyId/kill— emergency kill-switch (scoped to your org).POST /v1/api-keys/:keyId/rotate— rotate the secret, old one becomes invalid on the next request.DELETE /v1/api-keys/:keyId— retire a key without tripping the kill-switch.
When to revoke
- A key appeared in a git commit, a log file, or any place you can't scrub completely.
- An employee with access to a key left.
- Any suspicion the secret is out of your control.
Rotating is free. Revoking is free. We'd rather see five false alarms than miss one real leak.
Kill-switch semantics
The kill switch is a per-key (or per-org, or global) boolean that short-circuits request handling after authentication but before business logic. It returns 503 KILL_SWITCH with details.scope ∈ {"key", "organization", "global"}.
We flip it ourselves in two cases:
- Runaway client — you're paging an upstream platform at a rate that risks getting Layers or your app rate-limited by Meta/TikTok/Apple. We'd rather stop you than let a cascading ban happen. You'll hear from us on your partner channel the same minute.
- Upstream incident — a platform is down in a way where retrying makes things worse. Global kill buys the ecosystem time to recover.
A kill is never silent. We post to the support and message your partner contact.
Responsible disclosure
If you find a vulnerability, email security@layers.com with repro steps and the requestId of any affected request. We aim to reply promptly and will not pursue legal action against good-faith researchers operating within the standard safe-harbor terms.
Layers does not currently run a paid bug-bounty program.
Please do not open public GitHub issues for vulnerabilities.