DeveloperAPI & edge functions

API. Edge functions and the service layer.

Plooi uses Supabase Edge Functions for every server-side operation — AI proxying, billing, BYOK key handling, account lifecycle.

Edge functions

FunctionPurposeAuth
ai-proxyRoutes AI requests, decrypts BYOK keys server-side, checks credits, logs usageUser token
ai-job-workerAsync job queue for long-running runsService role
store-api-keyEncrypts and stores a user’s provider key (AES-256-GCM + HKDF-SHA256)User token
delete-api-keyRemoves a stored provider keyUser token
validate-api-keyLive-checks a key against the provider before storingUser token
get-capabilitiesReturns the model registry filtered to the user’s connected providersUser token
create-checkout-sessionStripe CheckoutUser token
create-portal-sessionStripe Customer PortalUser token
stripe-webhookProcesses Stripe events (atomic idempotency)Stripe signature
stripe-admin-statsAdmin reportingService role
retry-stripe-eventWebhook re-tryService role
password-hashHashes public link passwordsService role (cron-gated)
send-emailTransactional mail via ResendService role (cron-gated)
request-account-deletionGDPR deletion requestUser token
cancel-account-deletionCancel a pending deletionUser token
execute-account-deletionFinal deletion runService role
send-deletion-warningsReminder emails before deletionService role
export-user-dataGDPR data exportUser token
healthSystem health probePublic
changelog-createChangelog automationService role

Full request/response examples are in docs/API_REFERENCE.md.

BYOK key handling

The key-related edge functions are the only path that ever touches plaintext. The browser never writes or reads ciphertext.

  • store-api-key derives a 16-byte salt and 12-byte nonce, runs HKDF-SHA256 against the master key, then AES-256-GCM encrypts the plaintext and writes ciphertext to user_api_keys. The master key lives in Supabase Function secrets — outside Postgres.
  • ai-proxy is the only function that decrypts. It pulls the row server-side, decrypts in memory, makes the provider call, then discards the plaintext.
  • Browser reads go through the user_api_keys_public view — only id, service_name, key_hint (last four chars), and key_version. The ciphertext column is REVOKEd from the authenticated role.
  • Every save, delete, and validate is written to the audit log without plaintext.

See Bring your own key for the full encryption model.

Service layer (frontend)

Key services in the browser-side codebase:

  • authService — auth and session
  • projectService — projects, nodes, connections
  • aiServerService / aiJobService — AI runs and queue
  • stripeService / creditLedgerService — billing and credits
  • collaborationService — realtime and presence
  • adminService — admin functions
  • analyticsService / featureFlagService — events and flags