Skip to main content

Edge Functions Overview

Client Portal uses 39 Deno edge functions deployed on Supabase Cloud. Edge functions handle all external integrations, webhook ingestion, OAuth flows, AI processing, and email sending. They are the only server-side code in the system -- the React frontend talks directly to Supabase for all data operations.

Runtime

PropertyValue
RuntimeDeno (NOT Node.js)
Locationsupabase/functions/
Configsupabase/config.toml
JWT VerificationDisabled (verify_jwt = false) for all functions
Deploymentsupabase functions deploy <name>
Local Testingsupabase functions serve
Secretssupabase secrets set KEY=value
Deno, Not Node

Edge functions run on Deno, not Node.js. This means:

  • Use import from URLs, not require
  • Use Deno.env.get() instead of process.env
  • npm packages are imported via https://esm.sh/ or https://deno.land/x/
  • TypeScript works natively without compilation

Function List

All 39 edge functions organized by category:

Calendar & OAuth (4)

FunctionPurpose
google-calendar-callbackGoogle OAuth callback, upserts calendar tokens
outlook-calendar-callbackOutlook OAuth callback, upserts calendar tokens
get-calendar-availabilityCheck busy times for booking page
create-calendar-eventCreate event in Google/Outlook calendar

Booking & Meetings (4)

FunctionPurpose
send-booking-notificationBooking confirmation email via Resend
send-meeting-reminder24h and 1h meeting reminder emails
cancel-meetingHandle meeting cancellation
check-no-showsDetect missed meetings

GHL Integration (4)

FunctionPurpose
ghl-call-webhookClient campaign call webhook from GHL
ghl-sales-webhookInternal sales call webhook from GHL
sync-prospects-to-ghlPush prospects to GHL contacts
pull-from-ghlPull contacts and calls from GHL

Enrichment (10)

FunctionPurpose
blitz-enrich-attorney-contactsEnrich email + phone via Blitz API
blitz-update-sparse-attorneysUpdate incomplete attorney records
enrich-firm-attorneysBulk enrich attorneys at a specific firm
enrich-contacts-pipelineGeneral contact enrichment pipeline
search-attorney-profile-urlsFind attorney bio URLs on firm websites
find-attorney-urlsAlternative attorney URL finder
detect-firm-url-patternsDetect URL pattern for a firm's attorney pages
scrape-attorney-profilesWeb scraping of firm attorney pages
match-profile-urls-to-attorneysLink scraped URLs to attorney records
populate-firm-websitesBackfill firm website URLs

Market Population (3)

FunctionPurpose
populate-marketCreate/populate a market definition
populate-market-attorneysLink attorneys to a market
preview-firm-attorneysPreview attorneys at a firm before populating

AI (1)

FunctionPurpose
summarize-sales-callClaude AI transcript summarization

CRM (2)

FunctionPurpose
create-close-leadCreate a lead in Close CRM
close-webhook-handlerHandle incoming Close CRM webhooks

Apollo (3)

FunctionPurpose
apollo-enrich-companyEnrich company data from Apollo
apollo-enrich-sales-companyEnrich sales company from Apollo
apollo-org-searchSearch organizations in Apollo
apollo-search-firm-attorneysSearch firm attorneys in Apollo

Notifications (3)

FunctionPurpose
send-onboarding-emailWelcome email to new clients
send-slack-notificationSlack webhook for meeting updates
fathom-meeting-webhookIncoming webhook from Fathom

User Management (2)

FunctionPurpose
invite-userSend user invitation
delete-userDelete a user account

Data (2)

FunctionPurpose
check-data-readinessVerify data prerequisites
retry-transcript-fetchRetry failed transcript downloads

Common Patterns

CORS Handling

Every edge function starts with CORS headers to allow requests from the frontend:

const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

Deno.serve(async (req) => {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}

try {
// Function logic here
return new Response(JSON.stringify({ success: true }), {
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
});
}
});

Supabase Client Initialization

Edge functions create a Supabase admin client using the service role key (bypasses RLS):

import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);

For functions that need to respect the calling user's permissions, use the user's JWT:

const authHeader = req.headers.get('Authorization')!;
const supabaseUser = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!,
{ global: { headers: { Authorization: authHeader } } }
);

Environment Variables

Access secrets set via supabase secrets set:

const apiKey = Deno.env.get('BLITZ_API_KEY');
const anthropicKey = Deno.env.get('ANTHROPIC_API_KEY');

Configuration

All functions are configured in supabase/config.toml with JWT verification disabled:

[functions.google-calendar-callback]
verify_jwt = false

[functions.ghl-sales-webhook]
verify_jwt = false

# ... repeated for all 39 functions
Why verify_jwt = false?

JWT verification is disabled because:

  1. Webhook endpoints receive requests from external services (GHL, Fathom) that do not have a Supabase JWT.
  2. OAuth callbacks receive redirects from Google/Outlook that do not have a JWT.
  3. All other functions receive the JWT in the Authorization header and can validate it manually if needed.

For functions called from the frontend, the Supabase client automatically includes the JWT in the Authorization header.

Deployment

Deploy a single function

supabase functions deploy ghl-sales-webhook

Deploy all functions

supabase functions deploy

Set secrets

supabase secrets set ANTHROPIC_API_KEY=sk-ant-...
supabase secrets set BLITZ_API_KEY=...

View logs

# Stream logs for a specific function
supabase functions logs ghl-sales-webhook

# Or view in the Supabase dashboard: Functions > Logs

Local development

# Serve all functions locally
supabase functions serve

# Serve a specific function
supabase functions serve ghl-sales-webhook