Edge Functions Overview¶
This page catalogs the Supabase Edge Functions under supabase/functions/: what each one does, how it is triggered, and which flows depend on it.
All edge functions run in Deno with the service role key. They must never be called directly from untrusted clients without appropriate auth checks.
Billing & subscriptions (Stripe)¶
stripe-webhook¶
Path: supabase/functions/stripe-webhook/index.ts
Trigger: HTTPS webhook from Stripe
HTTP method: POST (Stripe webhooks)
Purpose: Central handler for Stripe events.
Responsibilities:
- Verify the
stripe-signatureheader usingSTRIPE_WEBHOOK_SECRET. - Enforce idempotency via the
webhook_events_processedtable. - Resolve
company_idvia:event.data.object.metadata.company_id- Subscription metadata
- Checkout Session metadata
- Existing
subscriptionsrow - Customer metadata
- Handle key event types:
checkout.session.completed→ create/activate subscription row insubscriptions.customer.subscription.created/updated→ keep subscription row in sync.customer.subscription.deleted→ mark subscription as canceled (with “upgrade cancellation” nuance).invoice.payment_succeeded→ insert intopayment_history.
- Record outcome in
webhook_events_processedwith status and error info.
Inputs:
- Raw Stripe webhook payload.
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEYenv vars.
Outputs:
- 2xx on success or already-processed events.
- Error response on invalid signature or missing
company_id.
Used by flows:
create-checkout-session¶
Path: supabase/functions/create-checkout-session/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Create a Stripe Checkout Session for subscription signup/upgrade.
Responsibilities:
- Authenticate the caller via Supabase JWT (
Authorization: Bearer <token>). - Use Supabase service role to:
- Verify user and tenant.
- Load company info from
companies. - Check for existing
stripe_customer_idinsubscriptions, or create a new Stripe customer.
- Choose a Stripe Price ID based on
plan_nameusing env vars:STRIPE_STARTER_PRICE_IDSTRIPE_PROFESSIONAL_PRICE_ID
- Create a Stripe Checkout Session with:
- Mode:
subscription - Payment method collection:
always(collect card at trial start). - Metadata:
company_id,plan_name,source,feature,user_id,referral. - Success URL:
/checkout/success(includessession_id). - Cancel URL:
/checkout/cancel.
- Mode:
- Return
session.urlto the frontend.
Inputs (JSON body):
company_id(required)plan_name(required, e.g.starterorprofessional)- Optional:
source,feature,user_id,referral
Outputs:
{ url: string }– Stripe Checkout URL.
Used by flows:
- Signup + upgrade flows in Auth Flow.
- Billing & Stripe Flow.
create-portal-session¶
Path: supabase/functions/create-portal-session/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Create a Stripe Billing Portal Session for managing subscriptions.
Responsibilities:
- Authenticate user via Supabase JWT.
- Look up the tenant’s current subscription in
subscriptions. - Ensure
stripe_customer_idis known:- If missing, fetch subscription from Stripe and persist
stripe_customer_id.
- If missing, fetch subscription from Stripe and persist
- Create a Billing Portal session with:
customer = stripe_customer_id.return_urlpointing back to the dashboard.
- Return portal
url.
Inputs:
- JSON body:
{ company_id: string }.
Outputs:
{ url: string }– Stripe Billing Portal URL.
Used by flows:
- Billing & Stripe Flow (billing settings page).
get-stripe-subscription¶
Path: supabase/functions/get-stripe-subscription/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Fetch the current subscription from Stripe for accuracy.
Responsibilities:
- Authenticate user.
- Look up latest
subscriptionsrow forcompany_id. - Call Stripe
subscriptions.retrieve(stripe_subscription_id). - Map Stripe’s status and fields to an app-level object, including:
status(trial,active,past_due,canceled,expired).- Amount, currency, interval.
current_period_start,current_period_end.trial_end,trial_days_remaining.
Inputs:
- JSON body:
{ company_id: string }.
Outputs:
- Subscription summary object returned as JSON.
Used by flows:
- Billing UI to show accurate subscription state.
get-upcoming-invoice¶
Path: supabase/functions/get-upcoming-invoice/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Fetch upcoming invoice amounts from Stripe.
Responsibilities:
- Authenticate user.
- Look up
stripe_subscription_idandstripe_customer_idforcompany_id. - If subscription is in trial, return 0 due.
- Call
stripe.invoices.retrieveUpcoming. - Return:
amount_due(formatted as dollars).currency.next_payment_date.is_trialflag.
Inputs:
- JSON body:
{ company_id: string }.
Outputs:
{ amount_due, currency, next_payment_date, is_trial }.
Used by flows:
- Billing UI for “next payment” info.
get-customer-invoices¶
Path: supabase/functions/get-customer-invoices/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Fetch historical invoices from Stripe for a given customer.
Responsibilities:
- Authenticate user.
- Accept
stripe_customer_idand optionalstatusfilter. - Call
stripe.invoices.list({ customer, status?, limit }). - Map Stripe invoices to a simple object:
amount,currencystatus(normalized)invoice_urlpaid_at,created_atinvoice_number
Inputs:
- JSON body:
{ stripe_customer_id: string, status?: string }.
Outputs:
{ invoices: [...], total }.
Used by flows:
- Billing UI, owner analytics, support tools.
reactivate-subscription¶
Path: supabase/functions/reactivate-subscription/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Help resubscribe tenants whose subscriptions were canceled or expired.
Responsibilities:
- Authenticate user.
- Look up most recent canceled/expired subscription for
company_id. - Determine plan, trial status, and whether they are still in a paid period.
- Create a Stripe Checkout Session for resubscribe, with metadata marking it as
is_resubscribe. - Handle remaining trial days or active paid period:
- If still in paid period, schedule new subscription start after
current_period_end. - If in trial and trial not expired, maintain remaining trial days.
- If still in paid period, schedule new subscription start after
Inputs:
- JSON body:
{ company_id: string }.
Outputs:
{ url: string }– resubscribe checkout URL.
Used by flows:
- Future “reactivate subscription” buttons in billing UI.
sync-stripe-subscriptions¶
Path: supabase/functions/sync-stripe-subscriptions/index.ts
Trigger: Internal (cron) via HTTP with secret or service role
HTTP methods: POST
Purpose: Daily batch sync to keep subscriptions in line with Stripe.
Responsibilities:
- Authenticate using
CRON_SECRETor service role token. - Fetch active/trial/past_due subscriptions from Supabase.
- For each, call
stripe.subscriptions.retrieve. - Update:
statusamount,currency,intervalcurrent_period_start,current_period_endcancel_at_period_end,canceled_attrial_days_remainingstripe_customer_id(ensuring it is set)
Used by flows:
- Background data hygiene; supports all billing-related views.
sync-payment-history¶
Path: supabase/functions/sync-payment-history/index.ts
Trigger: HTTPS call from authenticated frontend or internal task
HTTP methods: OPTIONS, POST
Purpose: Backfill or repair payment_history from Stripe.
Responsibilities:
- Authenticate user.
- Accept
company_idandstripe_customer_id. - Call
stripe.invoices.list({ customer, status: 'paid' }). - For each invoice:
- Skip if
payment_historyalready hasstripe_invoice_id. - Insert a new row with
amount,currency,status,invoice_url,paid_at,created_at.
- Skip if
Used by flows:
- Operations runbooks and support tools.
upgrade-checkout-session¶
Path: supabase/functions/upgrade-checkout-session/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Change plan (upgrade/downgrade) for an existing subscription by updating Stripe subscription items (no new checkout).
Responsibilities:
- Authenticate user.
- Look up current subscription for
company_id. - Validate plan change using
PLAN_HIERARCHY:starter→professional(upgrade) allowed.professional→starter(downgrade) allowed.
- Retrieve Stripe subscription.
- Update subscription’s price to target plan price ID.
- Respect proration and trial/downgrade behavior as implemented.
Inputs:
- JSON body:
{ company_id: string, plan_name: 'starter' | 'professional' | 'enterprise', source?, feature?, user_id?, referral? }.
Outputs:
- Updated subscription summary.
Used by flows:
- Future “change plan” actions from billing settings.
Nameplates & affiliates¶
generate-nameplate¶
Path: supabase/functions/generate-nameplate/index.ts
Trigger: HTTPS call from authenticated frontend
HTTP methods: OPTIONS, POST
Purpose: Generate AI-powered nameplate designs and store them.
Responsibilities:
- Authenticate user via Supabase JWT.
- Resolve
tenant_idfromuser_profiles. - Enforce monthly usage limits via
nameplate_usage(default: 20 per user per month). - Accept parameters:
name,metalType,purity,withDiamonds,font.
- Call OpenAI image API (DALL·E) with a generated prompt.
- Store image in Supabase Storage (
nameplatesbucket). - Insert
nameplatesandnameplate_usagerows. - Return image URL and metadata.
Inputs:
- JSON body:
{ name, metalType, purity?, withDiamonds, font }.
Outputs:
{ imageUrl, nameplateId, usageCount, usageLimit }(shape inferred; see function code).
Used by flows:
- Design studio / nameplate generation (surface in Library and design flows).
submit-affiliate-application¶
Path: supabase/functions/submit-affiliate-application/index.ts
Trigger: Public HTTPS call from marketing/affiliate landing
HTTP methods: OPTIONS, POST
Purpose: Securely collect affiliate applications with rate limiting and duplication protections.
Responsibilities:
- Enforce request size limit.
- Derive client IP from headers.
- Rate-limit via
affiliate_rate_limitstable (e.g., 5 submissions/hour per IP; block for 24h on abuse). - Validate and sanitize fields:
- Name, email, phone, website, business info.
- Prevent duplicate submissions using a
submission_hash(hash of email+IP). - Insert into
affiliate_applicationswith sanitized data.
Inputs:
- JSON body with affiliate form fields.
Outputs:
{ success: true }on accepted submission.
Used by flows:
- Affiliate signup from marketing site.
Summary¶
These edge functions provide the “backend glue” between the Vite frontend, Supabase, and external services like Stripe and OpenAI.
- Stripe-related functions handle subscriptions, billing, webhooks, and historical sync.
- Nameplate generation uses OpenAI + Storage to provide design assets.
- Affiliate submission safely handles public form data.
For table-level details referenced above, see: