Skip to main content
Three credentials, three rules:

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.

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.