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
| Property | Value |
|---|---|
| Runtime | Deno (NOT Node.js) |
| Location | supabase/functions/ |
| Config | supabase/config.toml |
| JWT Verification | Disabled (verify_jwt = false) for all functions |
| Deployment | supabase functions deploy <name> |
| Local Testing | supabase functions serve |
| Secrets | supabase secrets set KEY=value |
Edge functions run on Deno, not Node.js. This means:
- Use
importfrom URLs, notrequire - Use
Deno.env.get()instead ofprocess.env - npm packages are imported via
https://esm.sh/orhttps://deno.land/x/ - TypeScript works natively without compilation
Function List
All 39 edge functions organized by category:
Calendar & OAuth (4)
| Function | Purpose |
|---|---|
google-calendar-callback | Google OAuth callback, upserts calendar tokens |
outlook-calendar-callback | Outlook OAuth callback, upserts calendar tokens |
get-calendar-availability | Check busy times for booking page |
create-calendar-event | Create event in Google/Outlook calendar |
Booking & Meetings (4)
| Function | Purpose |
|---|---|
send-booking-notification | Booking confirmation email via Resend |
send-meeting-reminder | 24h and 1h meeting reminder emails |
cancel-meeting | Handle meeting cancellation |
check-no-shows | Detect missed meetings |
GHL Integration (4)
| Function | Purpose |
|---|---|
ghl-call-webhook | Client campaign call webhook from GHL |
ghl-sales-webhook | Internal sales call webhook from GHL |
sync-prospects-to-ghl | Push prospects to GHL contacts |
pull-from-ghl | Pull contacts and calls from GHL |
Enrichment (10)
| Function | Purpose |
|---|---|
blitz-enrich-attorney-contacts | Enrich email + phone via Blitz API |
blitz-update-sparse-attorneys | Update incomplete attorney records |
enrich-firm-attorneys | Bulk enrich attorneys at a specific firm |
enrich-contacts-pipeline | General contact enrichment pipeline |
search-attorney-profile-urls | Find attorney bio URLs on firm websites |
find-attorney-urls | Alternative attorney URL finder |
detect-firm-url-patterns | Detect URL pattern for a firm's attorney pages |
scrape-attorney-profiles | Web scraping of firm attorney pages |
match-profile-urls-to-attorneys | Link scraped URLs to attorney records |
populate-firm-websites | Backfill firm website URLs |
Market Population (3)
| Function | Purpose |
|---|---|
populate-market | Create/populate a market definition |
populate-market-attorneys | Link attorneys to a market |
preview-firm-attorneys | Preview attorneys at a firm before populating |
AI (1)
| Function | Purpose |
|---|---|
summarize-sales-call | Claude AI transcript summarization |
CRM (2)
| Function | Purpose |
|---|---|
create-close-lead | Create a lead in Close CRM |
close-webhook-handler | Handle incoming Close CRM webhooks |
Apollo (3)
| Function | Purpose |
|---|---|
apollo-enrich-company | Enrich company data from Apollo |
apollo-enrich-sales-company | Enrich sales company from Apollo |
apollo-org-search | Search organizations in Apollo |
apollo-search-firm-attorneys | Search firm attorneys in Apollo |
Notifications (3)
| Function | Purpose |
|---|---|
send-onboarding-email | Welcome email to new clients |
send-slack-notification | Slack webhook for meeting updates |
fathom-meeting-webhook | Incoming webhook from Fathom |
User Management (2)
| Function | Purpose |
|---|---|
invite-user | Send user invitation |
delete-user | Delete a user account |
Data (2)
| Function | Purpose |
|---|---|
check-data-readiness | Verify data prerequisites |
retry-transcript-fetch | Retry 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
JWT verification is disabled because:
- Webhook endpoints receive requests from external services (GHL, Fathom) that do not have a Supabase JWT.
- OAuth callbacks receive redirects from Google/Outlook that do not have a JWT.
- 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