> ## Documentation Index
> Fetch the complete documentation index at: https://docs.result.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Keys & security

> Which key goes where, and what actually protects your data.

Three credentials, three rules:

| Credential                     | Where it may live          | What it does                                      |
| ------------------------------ | -------------------------- | ------------------------------------------------- |
| `NEXT_PUBLIC_BACKEND_ANON_KEY` | Browser, app code          | Publishable client key - the SDK uses it          |
| `BACKEND_ADMIN_KEY`            | Terminal, server code only | Full admin control - the CLI uses it              |
| User session                   | Managed by the SDK         | Issued at sign-in, scopes every call to that user |

## The publishable key is public - plan for it

Anyone can read it out of your shipped frontend. That is by design. What
protects your data:

1. **Row-level security.** RLS tables scope rows to the signed-in user
   automatically. Keep RLS on (the default) for any per-user data.
2. **Signed-in-only writes.** Storage uploads reject anonymous callers.
3. **Functions as the trust boundary.** AI calls and email sends work with
   the publishable key - anyone holding it can drive spend. Put expensive or
   sensitive operations in a [serverless function](/sdk/functions).

## The admin key is never public

* Never in client code, never in `NEXT_PUBLIC_*` vars, never in the browser.
* It belongs in `.env.local` for the CLI, or server-side code only.
* Everything the CLI does (schema, buckets, secrets, payment keys) uses it -
  that's why setup is a terminal activity.

## Payments

Never fulfill an order from the success URL - anyone can open that URL.
Verified webhook events land in the `payments.webhook_events` table; drive
fulfillment from those rows. See [Payments](/sdk/payments).
