API Keys
Latch uses a two-key model: every “key pair” is one publishable key plus one secret key, sharing the same name.
The pair model
Section titled “The pair model”Each pair contains two keys with different audiences:
- Publishable key (
pk_...) — embedded in browsers. Drives access checks, event ingestion, and customer auth. If it leaks, an attacker can talk to your public API as the same anonymous origin a real visitor would; they cannot mutate subscriptions or read other publications’ data. - Secret key (
sk_...) — server-side only. Used for subscription mutations and any flow that should not run in a browser. If it leaks, treat it as compromised and rotate immediately.
The two keys are independent records — revoking one does not revoke the other, but the Revoke pair action in the dashboard removes both at once.
Creating a key pair
Section titled “Creating a key pair”Go to Settings > API Keys, give the pair a name (e.g. Production, Staging), and click Create Pair.
You receive both keys exactly once. The dashboard auto-downloads a latch-{name}.env file containing:
LATCH_PUBLISHABLE_KEY=pk_live_xxxLATCH_SECRET_KEY=sk_live_xxxYou can also use Copy as .env in the banner to copy the same content to your clipboard.
What each key can do
Section titled “What each key can do”| Capability | Publishable (pk_) | Secret (sk_) |
|---|---|---|
Check access (/api/v1/access/check) | Yes | No |
Send events (/api/v1/events) | Yes | No |
| Customer auth (register / login / refresh / logout / me) | Yes | Yes |
Lookup active subscription (/api/v1/subscriptions/me) | Yes (via JWT) | Yes |
Create checkout session (/api/v1/subscriptions/checkout) | Yes (via JWT) | Yes |
Create portal session (/api/v1/subscriptions/portal) | Yes (via JWT) | Yes |
Cancel subscription (/api/v1/subscriptions/cancel) | No | Yes |
“Yes (via JWT)” means the publishable key is accepted, but the customer must additionally be identified through a customer JWT in the Authorization: Bearer ... header — the publishable key alone never grants access to a specific customer’s data.
Access check and event ingestion explicitly reject secret keys to discourage shipping sk_ to browsers. Dashboard-admin CRUD routes use authenticated admin sessions, not API keys.
Test your key
Section titled “Test your key”Run this curl one-liner against your fresh publishable key. A successful call returns a JSON body with a granted boolean.
curl "https://latch-api.v3ck.com/api/v1/access/check?url=https://example.com/" \-H "X-API-Key: pk_live_..."If you get 401 Unauthorized, the key is wrong or revoked. If you get 403, double-check the URL belongs to a publication this key has access to.
Drop-in SDK example
Section titled “Drop-in SDK example”Use the publishable key in browser code. The SDK reads it once at init and reuses it for all subsequent calls.
<script type="module">import { init, checkAccess, identify } from 'https://latch-api.v3ck.com/sdk/latch.js';
// Initialize with your publishable key.init({ apiKey: 'pk_live_...', apiUrl: 'https://latch-api.v3ck.com',});
// Check access on premium pages.const result = await checkAccess();if (!result.granted) { console.log('Paywall:', result.paywallRule);}
// After your auth flow signs the user in, tell Latch who they are.identify('reader-id-from-your-auth');</script>Server-side example
Section titled “Server-side example”Use the secret key from your backend. The example below creates a Stripe-backed checkout session.
curl -X POST "https://latch-api.v3ck.com/api/v1/subscriptions/checkout" \-H "X-API-Key: sk_live_..." \-H "Content-Type: application/json" \-d '{ "priceId": "price_abc123", "customerId": "cus_abc123", "successUrl": "https://yoursite.com/success", "cancelUrl": "https://yoursite.com/cancel"}'The response contains the url you redirect the customer to.
Revocation
Section titled “Revocation”Revoking a key takes effect immediately and cannot be undone. The dashboard offers two actions:
- Revoke pair — removes both records in the pair. Use this when retiring an environment.
- Revoke individual key (the trash icon next to a single
pk_/sk_row) — removes one record only. Useful if a single key leaked but the other side is fine.
After revoke, create a new pair with a different name; do not re-use the old name in scripts that still reference it.