# Security & compliance (/docs/api/operational/security-and-compliance)



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](mailto:security@layers.com). PGP key available on request.

<Callout type="info">
  Commercial terms (signed DPA, custom retention, security questionnaires,
  audit reports) are negotiated at contract time. Contact
  [legal@layers.com](mailto:legal@layers.com).
</Callout>

## What data flows where [#what-data-flows-where]

Three classes of data cross the network:

1. **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.
2. **Customer SDK events.** Events your app emits via the Layers SDK to `in.layers.com`. These carry the app-supplied `user_id`, optional `email`, optional `phone`, device identifiers, and the event properties you put on the payload. See [PII handling at the SDK ingest](#pii-handling-at-the-sdk-ingest) below.
3. **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 [#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 [#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](/docs/api/operational/data-protection).

For security questionnaires, audit artifacts, or a signed DPA, email [legal@layers.com](mailto:legal@layers.com).

## Encryption [#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 [#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](/docs/api/operational/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-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 [#headers-partners-send]

```http
Authorization: Bearer lp_live_01HXZ9G7KMV2QX8Y1S5RJW3B7T.a4b3c2d1e0...
```

See [Authentication](/docs/api/getting-started/authentication) for the wire-level specifics.

## Key revocation [#key-revocation]

Three ways a key stops working, in operational precedence order:

1. **Kill switch** (`key.kill_switch = true`). Immediate. Responses carry `503 KILL_SWITCH`. Used for runaway clients or emergency shutoffs. Reversible without re-issuing the key. See [Rate limits → Kill switch](/docs/api/operational/rate-limits#kill-switch).
2. **Soft revoke** (`is_active = false` or `revoked_at` set). Permanent. Responses carry `401 REVOKED`. Used when a key is compromised, superseded, or the partnership ends. Not reversible — issue a fresh key.
3. **Organization-level kill** (`kill_switch.scope = "organization"`). All keys for the org fail with `503 KILL_SWITCH`. Contractual remedy only.

### Self-serve revocation [#self-serve-revocation]

* [`POST /v1/api-keys/:keyId/kill`](/docs/api/reference/api-keys/kill) — emergency kill-switch (scoped to your org).
* [`POST /v1/api-keys/:keyId/rotate`](/docs/api/reference/api-keys/rotate) — rotate the secret, old one becomes invalid on the next request.
* [`DELETE /v1/api-keys/:keyId`](/docs/api/reference/api-keys/delete) — retire a key without tripping the kill-switch.

### When to revoke [#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 [#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 [#responsible-disclosure]

If you find a vulnerability, email [security@layers.com](mailto: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](https://disclose.io/).

Layers does not currently run a paid bug-bounty program.

Please **do not** open public GitHub issues for vulnerabilities.

## See also [#see-also]

* [Data protection](/docs/api/operational/data-protection)
* [Status & support](/docs/api/operational/status-and-support)
* [Authentication](/docs/api/getting-started/authentication)
* [Rate limits](/docs/api/operational/rate-limits)
* [Webhooks](/docs/api/operational/webhooks)
