# unLocked CRM — API Reference

> Generated from a full scan of the codebase on 2026-08-23.
> Machine-readable version: [`public/openapi.json`](./public/openapi.json) (OpenAPI 3.1) — also served live at `GET https://gzigyepfasiumngxilai.supabase.co/functions/v1/openapi-spec`.

## Base URL

```
https://gzigyepfasiumngxilai.supabase.co/functions/v1
```

Every endpoint is a serverless edge function under this origin. The app itself is served from `https://app.unlockedcrm.ai` (plus white-label domains), but **all API calls go to the functions origin above**.

## Authentication (plain English)

There are four ways an endpoint can be protected:

| Scheme | How a client authenticates | Used by |
|---|---|---|
| **API key** | Send `x-api-key: sk_live_...` header. Keys are created in **Settings → API**, carry scoped per-resource permissions (read/create/update/delete), support IP allowlisting, and are rate-limited to **100 requests/minute**. | The Public API (`/public-api`) |
| **User JWT** | Sign in to the app (email/password, Google, etc.), take the session access token, and send `Authorization: Bearer <token>`. The function validates the user and applies their role/workspace scoping. | All app-facing internal functions |
| **Tool secret** | Server-to-server calls from the AI voice platform send a shared secret in the `X-Tool-Secret` header. Not usable by end users. | AI agent tool webhooks (book/cancel/reschedule appointment, mark DNC, …) |
| **Webhook signature** | The calling provider (Stripe, Twilio, Meta, HealthSherpa, Calendly, …) signs the request; the function verifies the signature or a per-endpoint secret. | Inbound webhook receivers |

Anonymous/public endpoints: `GET /openapi-spec`, `GET /public-api?resource=health`, plus public-facing form/booking/quote submit endpoints which are unauthenticated by design (they create leads/appointments for prospects).

### Scoped permissions (machine-readable)

OAuth 2.0 (authorization code + PKCE) and API keys use the **same named scopes**. Request the least-privilege set.

- Authorization server metadata: `https://unlockedcrm.ai/.well-known/oauth-authorization-server`
- Protected-resource metadata (RFC 9728): `https://unlockedcrm.ai/.well-known/oauth-protected-resource`
- OpenAPI security schemes: `OAuth2` (with `flows.authorizationCode.scopes`) and `ApiKeyAuth` (with `x-scopes`) in `https://unlockedcrm.ai/openapi.json`

| Scope | Grants |
|---|---|
| `read:contacts` / `write:contacts` | Read / create + update contact records |
| `read:leads` / `write:leads` | Read / create + update leads and pipeline records |
| `read:policies` / `write:policies` | Read / create + update policies, renewals, lapse status |
| `read:quotes` / `write:quotes` | Read / create + update quotes and comparisons |
| `read:commissions` / `write:commissions` | Read / write commission statements and reconciliation data |
| `read:tasks` / `write:tasks` | Read / create + update tasks and reminders |
| `read:appointments` / `write:appointments` | Read / create + update calendar appointments |
| `read:activities` / `write:activities` | Read / write activity and timeline history |
| `read:communications` / `write:communications` | Read call, SMS, email history / send messages and place calls |
| `read:agent_ai` / `write:agent_ai` | Read AI agent config and runs / trigger runs and update config |

Authorization endpoint: `https://mcp.unlockedcrm.ai/oauth?action=authorize` — Token endpoint: `https://mcp.unlockedcrm.ai/oauth?action=token` — Revocation: `https://mcp.unlockedcrm.ai/oauth?action=revoke`


## Error responses (JSON, always)

Every non-2xx response from the API is `application/json`. The API never returns HTML error pages to API clients. Machine-readable catalog: `https://unlockedcrm.ai/api/errors.json` and the `x-error-format` block plus `components.schemas.Error` in `https://unlockedcrm.ai/openapi.json`.

Envelope:

```json
{
  "error": {
    "code": "permission_denied",
    "message": "Permission denied for this resource or action.",
    "status": 403,
    "retryable": false,
    "resolution": "Request the scope named in error.required_scope and retry.",
    "required_scope": "write:leads",
    "request_id": "req_01J9ZC7Q2X5T",
    "docs_url": "https://unlockedcrm.ai/api#errors"
  }
}
```

| `error.code` | HTTP | Meaning | Retryable | How to resolve |
|---|---|---|---|---|
| `invalid_request` | 400 | Malformed request, missing parameter, or unknown `resource`. | No | Fix the `resource` query parameter or required body fields, then retry. |
| `unauthenticated` | 401 | Missing, malformed, or expired credentials. | No | Send a valid `x-api-key` header or `Authorization: Bearer <jwt>`. |
| `permission_denied` | 403 | Credentials lack the required scope. | No | Request the scope in `error.required_scope`, then retry. |
| `not_found` | 404 | Record or endpoint does not exist in this workspace. | No | Verify the `id`; do not retry the same request. |
| `conflict` | 409 | Duplicate key or concurrent update. | Once | Re-fetch the record, merge, retry once. |
| `validation_failed` | 422 | Field values failed validation. | No | Read `error.details[]` and correct the named fields. |
| `rate_limited` | 429 | Over 100 requests/minute for this key. | Yes | Wait `Retry-After` (or `error.retry_after_seconds`), then back off. |
| `internal_error` | 500 | Unexpected server error. | Yes | Retry with exponential backoff; quote `error.request_id` to support. |
| `upstream_error` | 502 | Downstream carrier or provider API failed. | Yes | Retry with exponential backoff. |

Agent guidance: branch on `error.code` (stable), not on `error.message` (human-readable, may change). Honor `error.retryable` and never retry a terminal code with the same payload.

## Public API (stable, external-facing)

Single endpoint, four methods. The `resource` query parameter selects the collection; the HTTP method selects the operation.

| Method | Path | Query params | Body | Description |
|---|---|---|---|---|
| GET | `/public-api` | `resource` (required), `id`, `limit` (max 100, default 50), `offset`, `sort` (`field:dir`), `fields`, `search`, `status` | — | List a collection, or fetch one record by `id`. |
| POST | `/public-api` | `resource` (required), `action=bulk` | Record object, or `{mode, records[]}` for bulk (max 1,000) | Create one record, or bulk-create. |
| PUT | `/public-api` | `resource`, `id` (both required) | Record fields to update | Update a record. |
| DELETE | `/public-api` | `resource`, `id` (both required) | — | Delete a record. |

**Resources:** leads, clients, activities, tasks, policies, appointments, communications, webhooks, pipelines, pipeline_stages, opportunities, workflows, email_campaigns, commissions, aca_leads, agent_ai_call_logs, agent_ai_scripts, agent_ai_campaigns, quotes, tags, call_recordings, call_disposition_logs, agent_presence, inbound_campaigns, inbound_vendors — plus meta resources `health` (no auth) and `whoami`.

**Lead field aliases** (auto-rewritten on write): `income`→`household_income`, `annual_income`→`household_income`, `dob`→`date_of_birth`, `zipcode`/`postal_code`→`zip_code`, `phone_number`/`mobile`→`phone`, `company`→`employer`, `job_title`→`occupation`. Unknown keys are matched against workspace custom fields (case-insensitive: `variable_name` → `field_key` → `name`).

**Outbound webhooks you can subscribe to** via `resource=webhooks`: lead.created, lead.updated, lead.deleted, lead.status_changed, client.created, client.updated, task.created, task.completed, policy.created, policy.renewed, appointment.created, appointment.cancelled, activity.created, opportunity.created, opportunity.updated, opportunity.stage_changed, workflow.activated, workflow.deactivated, email_campaign.sent, email_campaign.completed, commission.created, commission.updated, sms.sent, sms.received, sms.delivered, sms.failed, quote.saved.

### Sample: create a lead

```bash
curl -X POST 'https://gzigyepfasiumngxilai.supabase.co/functions/v1/public-api?resource=leads' \
  -H 'x-api-key: sk_live_xxxxxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "phone": "+15551234567",
    "source": "Website",
    "income": "85000",
    "custom_fields": { "preferred_contact_time": "Evenings" }
  }'
```

**Response `200 OK`:**

```json
{
  "data": {
    "id": "7f3a9c2e-…",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@example.com",
    "phone": "+15551234567",
    "household_income": "85000",
    "source": "Website",
    "status": "new",
    "created_at": "2026-08-23T20:00:00.000Z"
  },
  "matched_custom_fields": ["preferred_contact_time"],
  "unknown_fields": []
}
```

## Internal edge functions (full catalog)

These power the app UI, AI, telephony, quoting, and integrations. They accept JSON bodies; request shapes are function-specific and **not** covered by the public API stability guarantee. All support `OPTIONS` preflight. `cron` = also invoked on a schedule by pg_cron.


### AI & Agents (93)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `agent-activity-summary` | `…/functions/v1/agent-activity-summary` | POST | User JWT (Bearer) |  | Resolve caller's role from database — never trust client input |
| `agent-ai-call` | `…/functions/v1/agent-ai-call` | POST | User JWT (Bearer) |  | Call-source attribution, forwarded verbatim to the EL-native path via the `...body` spread below and written to agent_ai_call_logs there. Declared |
| `agent-ai-call-control` | `…/functions/v1/agent-ai-call-control` | POST | User JWT (Bearer) |  | Handle CORS preflight requests |
| `agent-ai-call-handler` | `…/functions/v1/agent-ai-call-handler` | POST | User JWT (Bearer) |  | Global map for tracking call-specific state |
| `agent-ai-call-listen` | `…/functions/v1/agent-ai-call-listen` | POST | User JWT (Bearer) |  | agent-ai-call-listen Browser-facing WebSocket endpoint that lets agency users live-listen to an |
| `agent-ai-call-resume` | `…/functions/v1/agent-ai-call-resume` | POST | User JWT (Bearer) |  | TwiML Resume Endpoint When the agent-ai-call-handler edge function hits its wall-clock timeout, |
| `agent-ai-call-status` | `…/functions/v1/agent-ai-call-status` | POST | Provider webhook signature |  | Note: This is a Twilio webhook that returns TwiML - CORS headers are not needed Twilio webhooks use POST only and don't go through browser CORS checks |
| `agent-ai-campaign-processor` | `…/functions/v1/agent-ai-campaign-processor` | POST | User JWT (Bearer) | ✓ | PROCESSOR BUDGET `BATCH_SIZE` was removed: per-tick per-campaign concurrency is now bounded |
| `agent-ai-campaign-status` | `…/functions/v1/agent-ai-campaign-status` | POST | User JWT (Bearer) |  | agent-ai-campaign-status Phase 2.5 §4.5 B3 — derived runtime state for the campaign list / detail UI. |
| `agent-ai-campaign-summary` | `…/functions/v1/agent-ai-campaign-summary` | POST | User JWT (Bearer) |  | Agent Ai Campaign Summary function. |
| `agent-ai-clone-voice` | `…/functions/v1/agent-ai-clone-voice` | POST | User JWT (Bearer) |  | Returns null if the caller is allowed to create another voice clone, or a Response describing why they aren't. Enforces "Max plans get unlimited |
| `agent-ai-elevenlabs-backfill-recordings` | `…/functions/v1/agent-ai-elevenlabs-backfill-recordings` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-backfill-recordings One-time (idempotent, re-runnable) backfill: walks every historical |
| `agent-ai-elevenlabs-book-appointment` | `…/functions/v1/agent-ai-elevenlabs-book-appointment` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-book-appointment EL server tool: creates an appointment after the caller confirmed a |
| `agent-ai-elevenlabs-cancel-appointment` | `…/functions/v1/agent-ai-elevenlabs-cancel-appointment` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-cancel-appointment EL server tool: cancels an existing scheduled appointment for the |
| `agent-ai-elevenlabs-find-slots` | `…/functions/v1/agent-ai-elevenlabs-find-slots` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-find-slots EL server tool: returns available appointment slots for the contact's |
| `agent-ai-elevenlabs-import-phone` | `…/functions/v1/agent-ai-elevenlabs-import-phone` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-import-phone Stage 2 of the EL-native pilot productionization. Imports a CRM-managed |
| `agent-ai-elevenlabs-inbound-personalization` | `…/functions/v1/agent-ai-elevenlabs-inbound-personalization` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-inbound-personalization Fired by ElevenLabs before its inbound agent answers the call. We respond |
| `agent-ai-elevenlabs-mark-dnc` | `…/functions/v1/agent-ai-elevenlabs-mark-dnc` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-mark-dnc EL server tool: adds the caller's number to the subaccount's DNC list |
| `agent-ai-elevenlabs-outbound-call` | `…/functions/v1/agent-ai-elevenlabs-outbound-call` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-outbound-call EL-native replacement for the legacy `agent-ai-call` outbound path. Lifts |
| `agent-ai-elevenlabs-pilot-check` | `…/functions/v1/agent-ai-elevenlabs-pilot-check` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-pilot-check Returns { pilot: boolean } for the requested subaccount. Used by the |
| `agent-ai-elevenlabs-reconcile-stuck` | `…/functions/v1/agent-ai-elevenlabs-reconcile-stuck` | POST | User JWT (Bearer) | ✓ | agent-ai-elevenlabs-reconcile-stuck The single authority for resolving non-terminal ElevenLabs-native call_logs. |
| `agent-ai-elevenlabs-remove-inbound-phone` | `…/functions/v1/agent-ai-elevenlabs-remove-inbound-phone` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-remove-inbound-phone The inverse of `agent-ai-elevenlabs-import-phone` with direction='inbound': |
| `agent-ai-elevenlabs-remove-phone` | `…/functions/v1/agent-ai-elevenlabs-remove-phone` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-remove-phone Phase 2 multi-outbound: remove a CRM phone number's ElevenLabs binding. |
| `agent-ai-elevenlabs-repair-sms-webhooks` | `…/functions/v1/agent-ai-elevenlabs-repair-sms-webhooks` | POST | Provider webhook signature |  | agent-ai-elevenlabs-repair-sms-webhooks One-off, operator-triggered repair for phone numbers whose Twilio SMS |
| `agent-ai-elevenlabs-reschedule-appointment` | `…/functions/v1/agent-ai-elevenlabs-reschedule-appointment` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-reschedule-appointment EL server tool: moves an existing scheduled appointment to a new slot. |
| `agent-ai-elevenlabs-transcript-proxy` | `…/functions/v1/agent-ai-elevenlabs-transcript-proxy` | POST | User JWT (Bearer) |  | agent-ai-elevenlabs-transcript-proxy Server-side proxy used by `LiveCallListenerDock`'s EL-native branch. |
| `agent-ai-elevenlabs-transfer` | `…/functions/v1/agent-ai-elevenlabs-transfer` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-transfer EL server tool: bridges the live Twilio call leg to a human number. |
| `agent-ai-elevenlabs-update-call-outcome` | `…/functions/v1/agent-ai-elevenlabs-update-call-outcome` | POST | Tool secret (`X-Tool-Secret`) |  | agent-ai-elevenlabs-update-call-outcome EL server tool: updates the call's outcome mid-call (e.g. when the agent |
| `agent-ai-elevenlabs-webhook` | `…/functions/v1/agent-ai-elevenlabs-webhook` | POST | Provider webhook signature |  | agent-ai-elevenlabs-webhook Ingests ElevenLabs post-call events and persists them into CRM. Single |
| `agent-ai-inbound-call` | `…/functions/v1/agent-ai-inbound-call` | POST | Provider webhook signature |  | Note: This is a Twilio webhook that returns TwiML - CORS headers are not needed Twilio webhooks use POST only and don't go through browser CORS checks |
| `agent-ai-realtime-token` | `…/functions/v1/agent-ai-realtime-token` | POST | User JWT (Bearer) |  | Handle CORS preflight requests |
| `agent-ai-reconcile-call` | `…/functions/v1/agent-ai-reconcile-call` | POST | User JWT (Bearer) |  | Reconciles an agent_ai_call_logs row against Twilio's actual call status. Used when status callbacks are missed/dropped, so we don't blindly mark |
| `agent-ai-script-generator` | `…/functions/v1/agent-ai-script-generator` | POST | User JWT (Bearer) |  | Generates or updates an Agent AI call script using Lovable AI. Returns structured JSON via tool-calling: name, openingScript, primaryScript, voicemailScript, bookingRules, objections[]. |
| `agent-ai-test-tools` | `…/functions/v1/agent-ai-test-tools` | POST | User JWT (Bearer) |  | Agent AI Test Tools — executes tool calls from the in-browser Test Sandbox. Modes: |
| `agent-ai-transfer-fallback` | `…/functions/v1/agent-ai-transfer-fallback` | POST | Provider webhook signature |  | Transfer Fallback Handler — Multi-Agent Cascade Called by Twilio when a <Dial> attempt completes (via the action= attribute). |
| `agent-ai-transfer-whisper` | `…/functions/v1/agent-ai-transfer-whisper` | POST | User JWT (Bearer) |  | Warm Transfer Whisper Briefing Called by Twilio's <Number url="..."> when the receiving agent picks up. |
| `agent-ai-translate-campaign-opening` | `…/functions/v1/agent-ai-translate-campaign-opening` | POST | User JWT (Bearer) |  | Thin auth wrapper: invoked from the UI on campaign create/edit to translate the script opening into the campaign language and cache it on |
| `agent-ai-translate-receptionist-greeting` | `…/functions/v1/agent-ai-translate-receptionist-greeting` | POST | User JWT (Bearer) |  | Thin auth wrapper: invoked from the Arwyn Receptionist tab on Save to translate the greeting into the receptionist language and cache it on |
| `agent-ai-tts` | `…/functions/v1/agent-ai-tts` | POST | User JWT (Bearer) |  | Handle CORS preflight requests |
| `agent-ai-voice-explore` | `…/functions/v1/agent-ai-voice-explore` | POST | User JWT (Bearer) |  | Agent AI demo: ElevenLabs Voice Library ("Explore" tab). Called ONLY by the demo Voice tab (src/pages/demo/agentAiDemo/tabs/VoiceTab.tsx). |
| `agent-ai-voice-fallback` | `…/functions/v1/agent-ai-voice-fallback` | POST | User JWT (Bearer) |  | agent-ai-voice-fallback Wired as the Voice URL **Fallback** on every active Twilio number. |
| `agent-builder-ai` | `…/functions/v1/agent-builder-ai` | POST | User JWT (Bearer) |  | agent-builder-ai Lightweight assistant for the AI Agents builder UI. Covers three modes: |
| `agent-builtin-scheduler` | `…/functions/v1/agent-builtin-scheduler` | POST | User JWT (Bearer) | ✓ | Built-in agent scheduler. Cron pings this once; it fans out to every (subaccount, user) tuple that has the agent enabled and invokes the worker. |
| `agent-chat` | `…/functions/v1/agent-chat` | POST | User JWT (Bearer) |  | CMS-aware Medicare & Health Insurance System Prompt This knowledge block enhances understanding of CMS rules, Medicare products, ACA, and transitions. |
| `agent-client-retention` | `…/functions/v1/agent-client-retention` | POST | User JWT (Bearer) |  | Agent Client Retention function. |
| `agent-coverage-opportunity` | `…/functions/v1/agent-coverage-opportunity` | POST | User JWT (Bearer) |  | Medicare Coverage Opportunity Agent Daily cron sweep that flags Medicare-related opportunities and creates tasks for human review. |
| `agent-insights` | `…/functions/v1/agent-insights` | POST | User JWT (Bearer) |  | Create AI prompt based on agent metrics |
| `agent-lead-conversion` | `…/functions/v1/agent-lead-conversion` | POST | User JWT (Bearer) | ✓ | Kill-switch guard |
| `agent-presence` | `…/functions/v1/agent-presence` | POST | User JWT (Bearer) |  | Agent Presence function. |
| `agent-revenue-integrity` | `…/functions/v1/agent-revenue-integrity` | POST | User JWT (Bearer) |  | ---- Normalization helpers (shared by dry-run + live run) ----------------- |
| `agent-user-dispatcher` | `…/functions/v1/agent-user-dispatcher` | POST | User JWT (Bearer) |  | agent-user-dispatcher: runs every minute via pg_cron. Finds active scheduled user_agents and invokes agent-user-executor for those |
| `agent-user-executor` | `…/functions/v1/agent-user-executor` | POST | User JWT (Bearer) | ✓ | agent-user-executor: runs user-built agents (Phase 5 Track B) Loads an agent + its triggers/conditions/actions, evaluates against records, |
| `ai-analytics-insights` | `…/functions/v1/ai-analytics-insights` | POST | User JWT (Bearer) |  | AUTH + SPEND GUARD |
| `ai-analyze-leads` | `…/functions/v1/ai-analyze-leads` | POST | User JWT (Bearer) |  | Fetch leads data |
| `ai-analyze-voice-profile` | `…/functions/v1/ai-analyze-voice-profile` | POST | User JWT (Bearer) |  | Ai Analyze Voice Profile function. |
| `ai-assistant-chat` | `…/functions/v1/ai-assistant-chat` | POST | User JWT (Bearer) |  | Input validation schema |
| `ai-automation-builder` | `…/functions/v1/ai-automation-builder` | POST | User JWT (Bearer) |  | Triggers are described by the model in flat, human terms and must be translated into the shape the config panel and the processors actually read. |
| `ai-build-workflow` | `…/functions/v1/ai-build-workflow` | POST | User JWT (Bearer) |  | Deterministic day math. The model's day arithmetic is not reliable — the same prompt has produced 125, 90 and 75 day spans on consecutive runs — so the |
| `ai-call-coaching` | `…/functions/v1/ai-call-coaching` | POST | User JWT (Bearer) |  | Returns a 200 response with not_ready=true so the UI can render a friendly empty state instead of a generic "non-2xx" error toast. Used when the call |
| `ai-call-summary` | `…/functions/v1/ai-call-summary` | POST | User JWT (Bearer) |  | Ai Call Summary function. |
| `ai-campaign-insights` | `…/functions/v1/ai-campaign-insights` | POST | User JWT (Bearer) |  | AUTH + SPEND GUARD |
| `ai-campaign-reports-insights` | `…/functions/v1/ai-campaign-reports-insights` | POST | User JWT (Bearer) |  | AUTH + SPEND GUARD |
| `ai-chat` | `…/functions/v1/ai-chat` | POST | User JWT (Bearer) |  | SECURITY: Dynamic CORS based on request origin - no more wildcard |
| `ai-chat-suggest-followups` | `…/functions/v1/ai-chat-suggest-followups` | POST | User JWT (Bearer) |  | Ai Chat Suggest Followups function. |
| `ai-commission-intelligence` | `…/functions/v1/ai-commission-intelligence` | POST | User JWT (Bearer) |  | Rate limiting |
| `ai-communication` | `…/functions/v1/ai-communication` | POST | User JWT (Bearer) |  | AUTHENTICATION - Mandatory |
| `ai-deep-research` | `…/functions/v1/ai-deep-research` | POST | User JWT (Bearer) |  | COMPREHENSIVE INSURANCE CARRIER KNOWLEDGE BASE v2 |
| `ai-form-builder` | `…/functions/v1/ai-form-builder` | POST | User JWT (Bearer) |  | AI Form Builder — generates and iterates form field arrays from natural language. Uses Lovable AI gateway with structured tool-calling for reliable JSON output. |
| `ai-generate-content` | `…/functions/v1/ai-generate-content` | POST | User JWT (Bearer) |  | Validation schema |
| `ai-generate-image` | `…/functions/v1/ai-generate-image` | POST | User JWT (Bearer) |  | Select model based on quality |
| `ai-generate-note` | `…/functions/v1/ai-generate-note` | POST | User JWT (Bearer) |  | AUTHENTICATION - Mandatory |
| `ai-generate-pdf` | `…/functions/v1/ai-generate-pdf` | POST | User JWT (Bearer) |  | Ai Generate Pdf function. |
| `ai-generate-sheets` | `…/functions/v1/ai-generate-sheets` | POST | User JWT (Bearer) |  | Ai Generate Sheets function. |
| `ai-generate-slides` | `…/functions/v1/ai-generate-slides` | POST | User JWT (Bearer) |  | Ai Generate Slides function. |
| `ai-generate-sms` | `…/functions/v1/ai-generate-sms` | POST | User JWT (Bearer) |  | AUTHENTICATION - Mandatory |
| `ai-insights` | `…/functions/v1/ai-insights` | POST | User JWT (Bearer) |  | Rate limiting |
| `ai-lead-insights` | `…/functions/v1/ai-lead-insights` | POST | User JWT (Bearer) |  | Get Supabase client |
| `ai-lead-score` | `…/functions/v1/ai-lead-score` | POST | User JWT (Bearer) |  | Deterministic lead scoring engine. Uses subaccount scoring_settings weights + bonus factors (recency, completeness, source quality). |
| `ai-map-csv-columns` | `…/functions/v1/ai-map-csv-columns` | POST | User JWT (Bearer) |  | Which importer is asking. Drives the domain vocabulary in the system prompt. Defaults to "contacts" so existing callers are unaffected. |
| `ai-market-briefing` | `…/functions/v1/ai-market-briefing` | POST | User JWT (Bearer) |  | Ai Market Briefing function. |
| `ai-newsletter-generate` | `…/functions/v1/ai-newsletter-generate` | POST | User JWT (Bearer) |  | Validate auth |
| `ai-pipeline-intelligence` | `…/functions/v1/ai-pipeline-intelligence` | POST | User JWT (Bearer) |  | ------- SSE helpers ------- |
| `ai-policy-intelligence` | `…/functions/v1/ai-policy-intelligence` | POST | User JWT (Bearer) |  | Rate limiting |
| `ai-predictive-insights` | `…/functions/v1/ai-predictive-insights` | POST | User JWT (Bearer) |  | Fetch last 90 days of call logs for this subaccount |
| `ai-sms-reply` | `…/functions/v1/ai-sms-reply` | POST | User JWT (Bearer) |  | AI SMS Auto-Reply Edge Function (v5 — Intelligence Upgrade) v5 improvements: |
| `ai-suggest-reply` | `…/functions/v1/ai-suggest-reply` | POST | User JWT (Bearer) |  | AUTHENTICATION - Mandatory |
| `ai-task-intelligence` | `…/functions/v1/ai-task-intelligence` | POST | User JWT (Bearer) |  | Rate limiting |
| `ai-tool-drift-check` | `…/functions/v1/ai-tool-drift-check` | POST | User JWT (Bearer) | ✓ | Runs one check; a thrown check degrades to a single info finding. |
| `ai-transform-crm-text` | `…/functions/v1/ai-transform-crm-text` | POST | User JWT (Bearer) |  | Ai Transform Crm Text function. |
| `ai-v2-status` | `…/functions/v1/ai-v2-status` | POST | User JWT (Bearer) |  | unLocked AI v2 — status endpoint. The side panel calls this (passing the currently SELECTED subaccount) to decide |
| `ai-workflow-bundle` | `…/functions/v1/ai-workflow-bundle` | POST | User JWT (Bearer) |  | Map a logical step "tool" to the edge function that executes it. |
| `ai-write-bulk-email` | `…/functions/v1/ai-write-bulk-email` | POST | User JWT (Bearer) |  | Edge function: ai-write-bulk-email Generates a Subject + HTML body for a bulk email using Lovable AI |
| `ai-write-bulk-sms` | `…/functions/v1/ai-write-bulk-sms` | POST | User JWT (Bearer) |  | Edge function: ai-write-bulk-sms Generates a single SMS message body using Lovable AI, scoped to the |

### Admin & Provisioning (14)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `add-team-seat` | `…/functions/v1/add-team-seat` | POST | User JWT (Bearer) |  | Claim state, declared out here rather than inside the try so the catch at the bottom can release a claim that was staked and provably never reached Stripe. |
| `admin-ban-user` | `…/functions/v1/admin-ban-user` | POST | User JWT (Bearer) |  | Verify caller is an admin or has internal secret |
| `admin-cancel-account` | `…/functions/v1/admin-cancel-account` | POST | User JWT (Bearer) |  | Verify caller is an admin |
| `admin-eo-compliance` | `…/functions/v1/admin-eo-compliance` | POST | User JWT (Bearer) |  | Verify user identity |
| `admin-legacy-migration-discover` | `…/functions/v1/admin-legacy-migration-discover` | POST | User JWT (Bearer) |  | admin-legacy-migration-discover READ-ONLY lookup for legacy GoHighLevel → unLocked CRM migration. |
| `admin-legacy-migration-migrate` | `…/functions/v1/admin-legacy-migration-migrate` | POST | User JWT (Bearer) |  | admin-legacy-migration-migrate Execute legacy GHL → CRM migration: |
| `admin-provision-user` | `…/functions/v1/admin-provision-user` | POST | User JWT (Bearer) |  | Ensure owner role |
| `provision-user-wallet` | `…/functions/v1/provision-user-wallet` | POST | User JWT (Bearer) |  | provision-user-wallet PHASE 2 — Per-User Per-Subaccount Wallet Infrastructure |
| `remove-team-seat` | `…/functions/v1/remove-team-seat` | POST | User JWT (Bearer) |  | OPTIONAL and additive. Absent means "no key", which is byte-identical to this function's behaviour before it existed — so any caller that does not |
| `temp-fix-login-mj` | `…/functions/v1/temp-fix-login-mj` | POST | User JWT (Bearer) |  | One-shot admin utility — support use only. Target: Manjinder "MJ" Jhamat (Raj Insurance Services) |
| `temp-set-password-brian` | `…/functions/v1/temp-set-password-brian` | POST | User JWT (Bearer) |  | One-shot admin utility — support use only. Target: Brian Bale (brian@tdhinsure.com -> support@tdhinsure.com) |
| `temp-set-password-keela` | `…/functions/v1/temp-set-password-keela` | POST | User JWT (Bearer) |  | One-shot admin utility — support use only. Target: Kellie Solo (kellie@solowealthgroup.com) |
| `temp-set-password-wendy` | `…/functions/v1/temp-set-password-wendy` | POST | User JWT (Bearer) |  | One-shot admin utility — support use only. Target: Wendy Beatty (login email wendy@forefrontbrokersolutions.com) |
| `temp-update-email` | `…/functions/v1/temp-update-email` | POST | User JWT (Bearer) |  | Temp Update Email function. |

### Automation & Scheduled Jobs (31)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `capability-nav-report` | `…/functions/v1/capability-nav-report` | POST | User JWT (Bearer) |  | unLocked AI v2 — navigation snapshot intake. The frontend POSTs its current navigation tree here. We authenticate the |
| `capability-scan` | `…/functions/v1/capability-scan` | POST | User JWT (Bearer) | ✓ | unLocked AI v2 — Capability Scan edge function. Thin HTTP wrapper around runFullScan(). Invoked by the Phase 3 pg_cron job |
| `capability-search` | `…/functions/v1/capability-search` | POST | User JWT (Bearer) |  | unLocked AI v2 — Capability Search (test harness). Standalone endpoint to verify the Phase 4 retrieval layer against the live |
| `process-abandoned-checkout` | `…/functions/v1/process-abandoned-checkout` | POST | User JWT (Bearer) |  | Abandoned Checkout Recovery Drip Runs via cron every hour. Finds users who signed up but never completed |
| `process-birthday-reminders` | `…/functions/v1/process-birthday-reminders` | POST | User JWT (Bearer) | ✓ | Local hour, in the workspace's own timezone, at which birthday outreach may start going out. The cron runs hourly and each workspace is skipped until its |
| `process-booking-nudges` | `…/functions/v1/process-booking-nudges` | POST | User JWT (Bearer) | ✓ | Booking-link SMS Nudge scheduler. Runs on a cron (every ~5 minutes). For each upcoming appointment that came |
| `process-campaigns` | `…/functions/v1/process-campaigns` | POST | User JWT (Bearer) | ✓ | BATCH CONFIGURATION FOR SCALE The send-sms ceiling is PER SUBACCOUNT, not global: check_high_cost_rate_limit is called |
| `process-cancellation-drip` | `…/functions/v1/process-cancellation-drip` | POST | User JWT (Bearer) |  | ============= EMAIL TEMPLATE HELPERS ============= |
| `process-custom-date-reminders` | `…/functions/v1/process-custom-date-reminders` | POST | User JWT (Bearer) | ✓ | Local hour, in the workspace's own timezone, at which nudges may start going out. The cron runs hourly and each workspace is skipped until its own clock |
| `process-enrollment-period` | `…/functions/v1/process-enrollment-period` | POST | User JWT (Bearer) | ✓ | process-enrollment-period Server-side replacement for the client-only useEnrollmentPeriodScanner hook. |
| `process-medicare-eligibility` | `…/functions/v1/process-medicare-eligibility` | POST | User JWT (Bearer) | ✓ | The age being turned. 65 (Medicare IEP) unless the workflow says otherwise. |
| `process-medicare-pending-eligible` | `…/functions/v1/process-medicare-pending-eligible` | POST | User JWT (Bearer) | ✓ | process-medicare-pending-eligible Server-side firing engine for the "Medicare Pending → Eligible" trigger |
| `process-nipr-alert-billing` | `…/functions/v1/process-nipr-alert-billing` | POST | User JWT (Bearer) |  | NIPR PDB ALERT MONTHLY BILLING Scheduled job to process monthly alert subscriptions |
| `process-onboarding-emails` | `…/functions/v1/process-onboarding-emails` | POST | User JWT (Bearer) |  | Subaccounts whose members should NOT receive onboarding drip emails |
| `process-onboarding-queue` | `…/functions/v1/process-onboarding-queue` | POST | User JWT (Bearer) |  | Processes the scheduled_onboarding_emails queue. Runs every minute via pg_cron. Picks up rows where send_at <= now() and sent = false, |
| `process-policy-renewal` | `…/functions/v1/process-policy-renewal` | POST | User JWT (Bearer) | ✓ | process-policy-renewal Server-side replacement for the client-only useRenewalScanner hook. The |
| `process-quote-attachment` | `…/functions/v1/process-quote-attachment` | POST | User JWT (Bearer) |  | Process Quote Attachment function. |
| `process-resend-unopened` | `…/functions/v1/process-resend-unopened` | POST | Provider webhook signature |  | Find campaigns with resendToUnopened enabled that are past their delay window |
| `process-scheduled-emails` | `…/functions/v1/process-scheduled-emails` | POST | User JWT (Bearer) |  | Load a scheduled campaign's attachments once, up front, so the bytes are reused across every recipient instead of being re-downloaded per send. |
| `process-scheduled-nudges` | `…/functions/v1/process-scheduled-nudges` | POST | User JWT (Bearer) | ✓ | Process Scheduled Nudges This edge function processes pending scheduled messages from the scheduled_messages table. |
| `process-scheduled-opportunities` | `…/functions/v1/process-scheduled-opportunities` | POST | User JWT (Bearer) | ✓ | Processes due rows in scheduled_opportunity_additions (Contacts → "Add/Update Opportunity", Scheduled & Drip modes). For each due row it creates the real |
| `process-scheduled-quote-sends` | `…/functions/v1/process-scheduled-quote-sends` | POST | User JWT (Bearer) | ✓ | Cron-driven processor that sends due scheduled quotes. Reads scheduled_quote_sends where status='pending' AND scheduled_for <= now(), |
| `process-sms-queue` | `…/functions/v1/process-sms-queue` | POST | User JWT (Bearer) |  | SMS Queue Processor — consumes sms_send_queue rows that were deferred due to 10DLC throughput limits (1 msg/sec/number). |
| `process-task-reminders` | `…/functions/v1/process-task-reminders` | POST | User JWT (Bearer) |  | Get current date (UTC midnight for comparison) |
| `process-workflow-jobs` | `…/functions/v1/process-workflow-jobs` | POST | User JWT (Bearer) |  | process-workflow-jobs (legacy compatibility entrypoint) Keep this function as a thin proxy only. The real processor is |
| `trigger-day0-onboarding` | `…/functions/v1/trigger-day0-onboarding` | POST | User JWT (Bearer) |  | Triggers Day 0 onboarding emails with staggered delays: - day0_welcome: immediately |
| `trigger-link-click` | `…/functions/v1/trigger-link-click` | POST | User JWT (Bearer) |  | Public endpoint hit when the React route /l/:slug loads. Records the click, fires trigger-workflow with triggerType='trigger_link_clicked' so any paused |
| `trigger-workflow` | `…/functions/v1/trigger-workflow` | POST | User JWT (Bearer) | ✓ | BOOKING LINK SAFEGUARD When a user has no active booking link, {{booking_link}}, {{user.calendar_link}}, |
| `webhook-dispatcher` | `…/functions/v1/webhook-dispatcher` | POST | Provider webhook signature | ✓ | Outbound webhook dispatcher. POST /functions/v1/webhook-dispatcher |
| `webhook-retry-worker` | `…/functions/v1/webhook-retry-worker` | POST | Provider webhook signature | ✓ | Webhook delivery retry worker Re-attempts failed webhook deliveries with exponential backoff: |
| `workflow-queue-listener` | `…/functions/v1/workflow-queue-listener` | POST | User JWT (Bearer) | ✓ | workflow-queue-listener Event-driven workflow job processor. Invoked by: |

### Billing & Payments (15)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `check-subscription` | `…/functions/v1/check-subscription` | POST | User JWT (Bearer) |  | Safely convert Stripe's current_period_end (unix seconds or already a Date/string) to ISO string |
| `commission-plus-activate` | `…/functions/v1/commission-plus-activate` | POST | User JWT (Bearer) |  | Commission Plus Activate function. |
| `create-checkout` | `…/functions/v1/create-checkout` | POST | User JWT (Bearer) |  | Server-side validation: only allow known Stripe price IDs |
| `deduct-wallet` | `…/functions/v1/deduct-wallet` | POST | User JWT (Bearer) |  | Context: docs/source-of-truth/BILLING_WALLET_SOURCE_OF_TRUTH.md |
| `lead-cap-billing-trigger` | `…/functions/v1/lead-cap-billing-trigger` | POST | User JWT (Bearer) | ✓ | Lead Cap Billing Trigger Invoked by DB trigger when an agent's remaining lead balance crosses the |
| `manual-recharge` | `…/functions/v1/manual-recharge` | POST | User JWT (Bearer) |  | Fund amounts available for wallet top-up (all in USD) |
| `marketplace-checkout` | `…/functions/v1/marketplace-checkout` | POST | User JWT (Bearer) |  | Get authenticated user |
| `rebill-subaccount` | `…/functions/v1/rebill-subaccount` | POST | User JWT (Bearer) |  | Call atomic rebill RPC — handles vendor cost deduction from agency wallet and markup-based deduction from sub-account wallet in a single transaction |
| `self-cancel-subscription` | `…/functions/v1/self-cancel-subscription` | POST | User JWT (Bearer) |  | The target `team_members` row, as read here. `TargetTeamMemberRow` is the subset authorizeMemberCancel decides on; the rest is what this handler needs |
| `stripe-advanced-support-webhook` | `…/functions/v1/stripe-advanced-support-webhook` | POST | Provider webhook signature |  | Helper function to send emails via Resend API (no SDK needed) |
| `stripe-kaleb-preview` | `…/functions/v1/stripe-kaleb-preview` | POST | User JWT (Bearer) |  | Temporary read-only diagnostic function — see docs/client-kaleb-dodson-upgrade-button/PREVIEW_FUNCTION_TECHNICAL.md |
| `stripe-max-audit` | `…/functions/v1/stripe-max-audit` | POST | User JWT (Bearer) |  | Temporary read-only audit function — see docs/client-kaleb-dodson-upgrade-button/ for the Kaleb investigation that triggered this. Surveys Max-plan subscriptions |
| `stripe-trial-audit-readonly` | `…/functions/v1/stripe-trial-audit-readonly` | POST | User JWT (Bearer) |  | TEMPORARY READ-ONLY audit function. Delete after use. Split into modes to stay under gateway timeout: ?mode=failed\|trialing\|descriptor |
| `stripe-webhook` | `…/functions/v1/stripe-webhook` | POST | Provider webhook signature |  | Safely convert Stripe's current_period_end (unix seconds or already a Date/string) to ISO string |
| `trigger-auto-recharge` | `…/functions/v1/trigger-auto-recharge` | POST | User JWT (Bearer) |  | Recharge tiers for smart adjustment |

### Calendar & Booking (1)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `calendar-cron-sync` | `…/functions/v1/calendar-cron-sync` | POST | User JWT (Bearer) |  | Server-side cron sync for calendar events Runs every 5 minutes as a fallback safety net |

### Core CRM (200)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `add-mailgun-domain` | `…/functions/v1/add-mailgun-domain` | POST | Provider webhook signature |  | Same resolution as verify-mailgun-domain and send-mailgun, so the domain is created in the account that will later be asked to verify it and send from it. |
| `analyze-policy` | `…/functions/v1/analyze-policy` | POST | User JWT (Bearer) |  | ===== SCANNED PDF / OCR DETECTION ===== Detect if a PDF is scanned (image-based) vs native (text-based) |
| `apply-invoice-coupon` | `…/functions/v1/apply-invoice-coupon` | POST | User JWT (Bearer) |  | Apply Invoice Coupon function. |
| `archive-audit-logs` | `…/functions/v1/archive-audit-logs` | POST | User JWT (Bearer) |  | Archive Audit Logs Edge Function PURPOSE: |
| `at-risk-trial-alert` | `…/functions/v1/at-risk-trial-alert` | POST | User JWT (Bearer) |  | Fetch all trialing subscriptions |
| `atlas-search` | `…/functions/v1/atlas-search` | POST | User JWT (Bearer) |  | State abbreviation mapping |
| `backfill-onboarding-pdfs` | `…/functions/v1/backfill-onboarding-pdfs` | POST | User JWT (Bearer) |  | One-shot backfill: re-sends the onboarding PDF email for users who completed onboarding in the last N days but whose admin notification never went out |
| `backfill-script-standard` | `…/functions/v1/backfill-script-standard` | POST | User JWT (Bearer) |  | backfill-script-standard Re-runnable sweep that brings agent_ai_scripts rows into full compliance with the |
| `backfill-wallet-payment-methods` | `…/functions/v1/backfill-wallet-payment-methods` | POST | User JWT (Bearer) |  | BACKFILL: Populate credit_wallets.default_payment_method_id from Stripe One-time admin script. NOT scheduled. NOT invoked automatically. |
| `build-compile` | `…/functions/v1/build-compile` | POST | User JWT (Bearer) |  | build-compile — Build v2 sandboxed code-gen pipeline. POST { source: string } |
| `build-edit-widget` | `…/functions/v1/build-edit-widget` | POST | User JWT (Bearer) |  | build-edit-widget Targeted, single-widget AI editing. |
| `build-entity-write` | `…/functions/v1/build-entity-write` | POST | User JWT (Bearer) |  | Entities that are READ-ONLY through the Build write surface. Reads still work via CRM.query / entity_table widgets; writes are blocked because they have |
| `build-generate` | `…/functions/v1/build-generate` | POST | User JWT (Bearer) |  | Generatable widget types (the AI tool-schema enum). EDGE-FN copy — MUST stay in sync with ALLOWED_WIDGET_TYPES in src/lib/builderValidation.ts. Locked by widgetTypeSync.test.ts. |
| `build-generate-code` | `…/functions/v1/build-generate-code` | POST | User JWT (Bearer) |  | build-generate-code — Build v2 generator (TSX + sandbox). POST { |
| `build-page-event` | `…/functions/v1/build-page-event` | POST | User JWT (Bearer) |  | build-page-event — Phase 4 dispatcher Single entrypoint for Page Automations. Looks up matching automations for a |
| `build-rollback` | `…/functions/v1/build-rollback` | POST | User JWT (Bearer) |  | build-rollback — restore a previously applied Build AI artifact. Permission model: |
| `build-safe-query` | `…/functions/v1/build-safe-query` | POST | User JWT (Bearer) |  | AI Safe Query Builder Translates natural-language analytics questions into safe, parameterized |
| `build-suggest-binding` | `…/functions/v1/build-suggest-binding` | POST | User JWT (Bearer) |  | build-suggest-binding AI-assisted data binding for the Build module. |
| `build-website-generate` | `…/functions/v1/build-website-generate` | POST | User JWT (Bearer) |  | build-website-generate — AI generator for PUBLIC insurance marketing sites & landing pages. Deliberately isolated from build-generate (the CRM dashboard generator): a marketing |
| `campaign-availability` | `…/functions/v1/campaign-availability` | POST | User JWT (Bearer) |  | Auth via API key |
| `campaign-lead-ping` | `…/functions/v1/campaign-lead-ping` | POST | User JWT (Bearer) |  | Auth via API key |
| `check-secrets` | `…/functions/v1/check-secrets` | POST | Provider webhook signature |  | List of all secrets we want to check |
| `check-stale-leads-sla` | `…/functions/v1/check-stale-leads-sla` | POST | User JWT (Bearer) |  | Scheduled edge function (weekly cron) that: #51 — Sends stale lead digest (leads with no activity 14+ days, status ≠ Won/Lost) |
| `check-stale-tickets` | `…/functions/v1/check-stale-tickets` | POST | User JWT (Bearer) |  | Auth: cron secret |
| `check-tasks-appointments` | `…/functions/v1/check-tasks-appointments` | POST | User JWT (Bearer) |  | Scheduled edge function that handles: #53 — Tasks due today (morning digest, in-app + email) |
| `check-whitelabel-dns` | `…/functions/v1/check-whitelabel-dns` | POST | User JWT (Bearer) |  | Verifies DNS for a self-serve white-label custom domain. Checks that both the root domain and its `www` variant resolve |
| `claim-team-seat` | `…/functions/v1/claim-team-seat` | POST | User JWT (Bearer) |  | Context: docs/source-of-truth/TEAM_INVITES_SOURCE_OF_TRUTH.md §15 (and §14 for the release side, which is unchanged here). |
| `cms-evaluate-eligibility` | `…/functions/v1/cms-evaluate-eligibility` | POST | User JWT (Bearer) |  | IEP starts 3 months before 65th birthday month |
| `complete-agent-payment-setup` | `…/functions/v1/complete-agent-payment-setup` | POST | User JWT (Bearer) |  | Try JWT auth first (works for both paths) |
| `compute-health-scores` | `…/functions/v1/compute-health-scores` | POST | User JWT (Bearer) |  | Fetch all subaccounts |
| `connect-icloud-calendar` | `…/functions/v1/connect-icloud-calendar` | POST | User JWT (Bearer) |  | Validate inputs |
| `contact-intelligence` | `…/functions/v1/contact-intelligence` | POST | User JWT (Bearer) |  | Verify user authentication |
| `create-data-checkout` | `…/functions/v1/create-data-checkout` | POST | User JWT (Bearer) |  | Licensed Agent Data product price IDs |
| `create-mailgun-inbound-route` | `…/functions/v1/create-mailgun-inbound-route` | POST | User JWT (Bearer) |  | Handle CORS preflight |
| `create-notification` | `…/functions/v1/create-notification` | POST | User JWT (Bearer) |  | Rate limiting |
| `create-portal-session` | `…/functions/v1/create-portal-session` | POST | User JWT (Bearer) |  | Find the user's Stripe customer ID |
| `create-team-user` | `…/functions/v1/create-team-user` | POST | User JWT (Bearer) |  | Create Team User Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `create-tiktok-review-user` | `…/functions/v1/create-tiktok-review-user` | POST | User JWT (Bearer) |  | Create TikTok Review User - Admin-only endpoint SECURITY: This function requires admin authentication and reads |
| `daily-no-call-digest` | `…/functions/v1/daily-no-call-digest` | POST | User JWT (Bearer) |  | onboarding progress |
| `data-proxy` | `…/functions/v1/data-proxy` | POST | User JWT (Bearer) |  | Initialize Supabase URL and anon key |
| `decay-memories` | `…/functions/v1/decay-memories` | POST | User JWT (Bearer) |  | Memory Decay Logic Reduces the relevance_weight of memories over time based on: |
| `delete-appointment` | `…/functions/v1/delete-appointment` | POST | User JWT (Bearer) |  | ===== Google helpers ===== |
| `delete-conversation` | `…/functions/v1/delete-conversation` | POST | User JWT (Bearer) |  | Authorized, complete deletion of a conversation (thread) from the Inbox. The client-side delete could only remove interaction rows the caller personally |
| `delete-secret` | `…/functions/v1/delete-secret` | POST | User JWT (Bearer) |  | Get environment variables once at the start |
| `delete-team-user` | `…/functions/v1/delete-team-user` | POST | User JWT (Bearer) |  | Delete Team User Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `diag-el-audit` | `…/functions/v1/diag-el-audit` | POST | User JWT (Bearer) |  | Diag El Audit function. |
| `diag-elevenlabs-pilot` | `…/functions/v1/diag-elevenlabs-pilot` | POST | User JWT (Bearer) |  | Diag Elevenlabs Pilot function. |
| `diag-inbound-routing` | `…/functions/v1/diag-inbound-routing` | POST | User JWT (Bearer) |  | diag-inbound-routing — RETIRED. Returns 410 Gone. Was a read-only diagnostic for the 2026-08-18 inbound-routing incident on |
| `diag-incident-1258` | `…/functions/v1/diag-incident-1258` | GET, POST | User JWT (Bearer) |  | READ-ONLY incident diagnostic for the 12:58Z regression on +15717123991 / phnum_9901. Calls EL GET /v1/convai/phone-numbers/{id} and Twilio GET /IncomingPhoneNumbers/{sid}.json. |
| `diag-meta-page-discovery` | `…/functions/v1/diag-meta-page-discovery` | POST | Provider webhook signature |  | READ-ONLY diagnostic for Ticket-655 — "only one Facebook Page appears under Available Pages". Answers, from Facebook itself rather than from our stored copy, WHY a Page is missing. |
| `disconnect-nipr` | `…/functions/v1/disconnect-nipr` | POST | User JWT (Bearer) |  | Verify the user has access to this subaccount |
| `domains-provision` | `…/functions/v1/domains-provision` | POST | User JWT (Bearer) |  | domains-provision (authenticated) — connect a custom domain to a website. Validates the caller owns the website, asks Cloudflare (or the stub adapter) to create a |
| `domains-verify` | `…/functions/v1/domains-verify` | POST | User JWT (Bearer) |  | domains-verify (authenticated) — re-check a custom domain's DNS/SSL status with Cloudflare and update the `domains` row. When status becomes "active", render-website will serve it. |
| `downline-ai-insights` | `…/functions/v1/downline-ai-insights` | POST | User JWT (Bearer) |  | Downline Ai Insights function. |
| `drug-intake-chat` | `…/functions/v1/drug-intake-chat` | POST | User JWT (Bearer) |  | Conversational AI Drug Intake Walks through medication capture via Q&A, asking follow-ups for dosage/frequency, |
| `el-pilot-diag` | `…/functions/v1/el-pilot-diag` | POST | Tool secret (`X-Tool-Secret`) |  | Temporary read-only diagnostic for EL pilot env + EL dashboard pull. No secrets are echoed. Returns presence/length/last4 only. |
| `elevenlabs-audio-isolation` | `…/functions/v1/elevenlabs-audio-isolation` | POST | User JWT (Bearer) |  | ElevenLabs Audio Isolation Edge Function Cleans noisy call recordings by isolating speech from background noise. |
| `elevenlabs-dubbing` | `…/functions/v1/elevenlabs-dubbing` | POST | User JWT (Bearer) |  | ElevenLabs Dubbing / Multi-language Edge Function Auto-translates agent AI scripts into other languages while preserving |
| `elevenlabs-tts` | `…/functions/v1/elevenlabs-tts` | POST | User JWT (Bearer) |  | Default to turbo v2.5 for speed (power dialer greetings, live scenarios) Use multilingual only when explicitly requested for quality |
| `embed-email-calendar` | `…/functions/v1/embed-email-calendar` | POST | User JWT (Bearer) |  | deno-lint-ignore-file no-explicit-any Background worker: generates 768-dim embeddings for emails + appointments |
| `embed-knowledge` | `…/functions/v1/embed-knowledge` | POST | User JWT (Bearer) |  | ===== IMPROVED CHUNKING: Section-aware with better overlap ===== |
| `end-impersonation` | `…/functions/v1/end-impersonation` | POST | User JWT (Bearer) |  | End Impersonation Edge Function SECURITY: Authenticated endpoint with restricted CORS |
| `enroll-campaign-contacts` | `…/functions/v1/enroll-campaign-contacts` | POST | User JWT (Bearer) |  | Get user from auth header |
| `execute-math-operation` | `…/functions/v1/execute-math-operation` | POST | User JWT (Bearer) |  | Get the contact to retrieve current field value |
| `extract-insurance-dictation` | `…/functions/v1/extract-insurance-dictation` | POST | User JWT (Bearer) |  | Extract Insurance Dictation function. |
| `extract-memories` | `…/functions/v1/extract-memories` | POST | User JWT (Bearer) |  | Call Lovable AI for extraction |
| `family-tree-insights` | `…/functions/v1/family-tree-insights` | POST | User JWT (Bearer) |  | Family Tree Insights function. |
| `fetch-nipr-entity` | `…/functions/v1/fetch-nipr-entity` | POST | User JWT (Bearer) |  | ─── Retry wrapper ──────────────────────────────────────────────────────────── |
| `fetch-twilio-full-recording` | `…/functions/v1/fetch-twilio-full-recording` | POST | Provider webhook signature |  | fetch-twilio-full-recording Stage 2.10 background sweep. For each `agent_ai_call_logs` row queued with |
| `fetch-twilio-recording` | `…/functions/v1/fetch-twilio-recording` | GET, POST | Provider webhook signature |  | Fetch Twilio Recording function. |
| `fraud-monitor` | `…/functions/v1/fraud-monitor` | POST | User JWT (Bearer) |  | Fraud monitor: scans recent signup_attempts and fires Slack alerts on suspicious activity. Designed to be called every 2 minutes by a cron / scheduler. Requires CRON_SECRET header. |
| `generate-admin-update` | `…/functions/v1/generate-admin-update` | POST | User JWT (Bearer) |  | Generate Admin Update function. |
| `generate-call-identity-vcf` | `…/functions/v1/generate-call-identity-vcf` | POST | User JWT (Bearer) |  | Generate Call Identity Vcf function. |
| `generate-call-summary` | `…/functions/v1/generate-call-summary` | POST | User JWT (Bearer) |  | Look up call context (direction, agent, contact) BEFORE the AI call so the model never inverts agent vs. contact roles. This mirrors the same fix |
| `generate-commission-insights` | `…/functions/v1/generate-commission-insights` | POST | User JWT (Bearer) |  | Generate Commission Insights function. |
| `generate-ics-invite` | `…/functions/v1/generate-ics-invite` | POST | User JWT (Bearer) |  | Format date to ICS format: YYYYMMDDTHHMMSSZ |
| `generate-onboarding-checklist` | `…/functions/v1/generate-onboarding-checklist` | POST | User JWT (Bearer) |  | Canonical feature catalog — the AI may ONLY select from these category: "ready" = auto-activated, "assisted" = team will help |
| `generate-retirement-pdf` | `…/functions/v1/generate-retirement-pdf` | POST | User JWT (Bearer) |  | Generate Retirement Pdf function. |
| `generate-soa-pdf` | `…/functions/v1/generate-soa-pdf` | POST | User JWT (Bearer) |  | Generate Soa Pdf function. |
| `get-call-transcript` | `…/functions/v1/get-call-transcript` | POST | User JWT (Bearer) |  | Returns the transcript for a call_recording or agent_ai_call_log. If transcript is missing but a recording_url exists, performs on-demand |
| `get-campaign-stats` | `…/functions/v1/get-campaign-stats` | POST | User JWT (Bearer) |  | Use user JWT to respect RLS |
| `get-downline-data` | `…/functions/v1/get-downline-data` | POST | User JWT (Bearer) |  | Validate user |
| `get-meeting-credentials` | `…/functions/v1/get-meeting-credentials` | POST | User JWT (Bearer) |  | supabase/functions/get-meeting-credentials/index.ts SECURITY: Returns Zoom meeting credentials (join URL, start URL, password, |
| `get-owner-plan-info` | `…/functions/v1/get-owner-plan-info` | POST | User JWT (Bearer) |  | Get Owner Plan Info function. |
| `get-stripe-publishable-key` | `…/functions/v1/get-stripe-publishable-key` | POST | User JWT (Bearer) |  | Get Stripe Publishable Key function. |
| `get-wallet` | `…/functions/v1/get-wallet` | POST | User JWT (Bearer) |  | Recharge tiers for smart adjustment |
| `grant-trial-bonus-day` | `…/functions/v1/grant-trial-bonus-day` | POST | User JWT (Bearer) |  | Daily cron: extend Stripe trial by 1 day for users whose AI took a real action yesterday, up to 7 bonus days. Triggered by pg_cron at 03:00 UTC. |
| `impersonate-user` | `…/functions/v1/impersonate-user` | POST | User JWT (Bearer) |  | Impersonate User Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `inbound-email-webhook` | `…/functions/v1/inbound-email-webhook` | GET, POST | Provider webhook signature |  | Verify Mailgun webhook signature (HMAC-SHA256) Mailgun signs webhooks with: signature = HMAC(SHA256, signing-key, timestamp + token) |
| `inbound-webhook` | `…/functions/v1/inbound-webhook` | POST | Provider webhook signature |  | Handle CORS preflight |
| `ingest-knowledge-pack` | `…/functions/v1/ingest-knowledge-pack` | POST | User JWT (Bearer) |  | ingest-knowledge-pack — platform admin uploads a carrier knowledge source (UW guide, brochure, rate sheet, commission schedule) and embeds it into |
| `insurance-news` | `…/functions/v1/insurance-news` | POST | User JWT (Bearer) |  | Run all queries in parallel instead of sequentially |
| `internal-backfill-weiss-dryrun` | `…/functions/v1/internal-backfill-weiss-dryrun` | POST | User JWT (Bearer) |  | One-shot dry-run wrapper for Richard Weiss Outlook backfill |
| `itk-quote` | `…/functions/v1/itk-quote` | POST | User JWT (Bearer) |  | itk-quote — Final Expense, Term & IUL quoting via Insurance Toolkits API (redeploy: pickup ITK_API_KEY) REQUIRED SUPABASE SECRETS: |
| `list-team-users` | `…/functions/v1/list-team-users` | POST | User JWT (Bearer) |  | List Team Users Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `load-recent-webhook-sample` | `…/functions/v1/load-recent-webhook-sample` | POST | Provider webhook signature |  | Verify access |
| `local-presence-reputation-check` | `…/functions/v1/local-presence-reputation-check` | POST | User JWT (Bearer) |  | Provider hook: returns null when no reputation provider is configured, which is currently always. Returning null is the designed no-op — the caller's |
| `log-admin-action` | `…/functions/v1/log-admin-action` | POST | User JWT (Bearer) |  | Log Admin Action Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `login-rate-limit` | `…/functions/v1/login-rate-limit` | POST | User JWT (Bearer) |  | Server-Side Login Rate Limiter Edge Function Checks and records failed login attempts per (email + IP). |
| `mcp-server` | `…/functions/v1/mcp-server` | POST | API key (`x-api-key`) |  | MCP (Model Context Protocol) server wrapper around the unLocked Public API. Lets AI agents (ChatGPT, Claude, Cursor) discover and call CRM tools natively. |
| `medicare-ppl-explain` | `…/functions/v1/medicare-ppl-explain` | POST | User JWT (Bearer) |  | Handle CORS preflight requests |
| `medicare-public-quote` | `…/functions/v1/medicare-public-quote` | POST | User JWT (Bearer) |  | Another adult in the household. Most Medigap carriers publish a discount for this — commonly 5–14% — and an agent applies it, so omitting it quoted |
| `npi-search` | `…/functions/v1/npi-search` | POST | User JWT (Bearer) |  | NPI Registry proxy - keeps NPPES traffic off the browser so the Lovable preview proxy / CORS quirks can't drop the request. |
| `oauth-callback` | `…/functions/v1/oauth-callback` | POST | User JWT (Bearer) |  | Rate limiting for security |
| `oauth-init` | `…/functions/v1/oauth-init` | POST | User JWT (Bearer) |  | Optional `login_hint`: pre-selects an account on the provider's chooser when the user has several signed in. It is a HINT only — the provider still shows its own sign-in and the user |
| `oauth-server` | `…/functions/v1/oauth-server` | GET, POST | User JWT (Bearer) |  | OAuth 2.0 Server for unLocked CRM Public API. Implements RFC 6749 (Authorization Code) + RFC 7636 (PKCE) + RFC 7009 (Revocation). |
| `onboarding-purchase-number` | `…/functions/v1/onboarding-purchase-number` | POST | User JWT (Bearer) |  | Onboarding wrapper around `twilio-phone-numbers` that automatically comps the very first phone number a subaccount has ever owned. Subsequent numbers |
| `openai-service` | `…/functions/v1/openai-service` | POST | User JWT (Bearer) |  | Build messages array |
| `openapi-spec` | `…/functions/v1/openapi-spec` | POST | User JWT (Bearer) |  | OpenAPI 3.1 specification for the unLocked CRM Public API. Served as a static JSON document so that AI agents (ChatGPT, Claude, |
| `parse-drugs` | `…/functions/v1/parse-drugs` | POST | User JWT (Bearer) |  | If image provided, run OCR via Gemini vision |
| `parse-eo-document` | `…/functions/v1/parse-eo-document` | POST | User JWT (Bearer) |  | Get user from token |
| `parse-pdf` | `…/functions/v1/parse-pdf` | POST | User JWT (Bearer) |  | Step 1: Try text extraction (handles both compressed and uncompressed streams) |
| `parse-providers` | `…/functions/v1/parse-providers` | POST | User JWT (Bearer) |  | Parse Providers function. |
| `portal-activation-notify` | `…/functions/v1/portal-activation-notify` | POST | User JWT (Bearer) |  | Sends two emails when a client first activates their portal: 1) Welcome email to the client |
| `portal-book-appointment` | `…/functions/v1/portal-book-appointment` | POST | User JWT (Bearer) |  | Books an appointment from the client portal. Reuses the agent's CRM availability rules + merges Google/Outlook busy |
| `postmaster-fetch` | `…/functions/v1/postmaster-fetch` | POST | User JWT (Bearer) |  | Get authenticated user |
| `prospector-webhook` | `…/functions/v1/prospector-webhook` | POST | Provider webhook signature |  | Prospector → CRM Webhook (Phase 2) Phase 2 additions: |
| `provider-calendar-event` | `…/functions/v1/provider-calendar-event` | POST | User JWT (Bearer) |  | Push, update, cancel, and RSVP calendar events directly on the user's connected Google Calendar or Outlook Calendar via their OAuth tokens. |
| `proxy-twilio-recording` | `…/functions/v1/proxy-twilio-recording` | POST | User JWT (Bearer) |  | Proxy Twilio Recording function. |
| `public-api` | `…/functions/v1/public-api` | POST | API key (`x-api-key`) |  | Public REST API v1 for unLocked CRM Authenticated via API keys (x-api-key header) |
| `public-appointment-cancel` | `…/functions/v1/public-appointment-cancel` | POST | User JWT (Bearer) |  | ===== Google helpers ===== |
| `public-appointment-reschedule` | `…/functions/v1/public-appointment-reschedule` | POST | User JWT (Bearer) |  | ===== Google helpers ===== |
| `recalculate-all-scores` | `…/functions/v1/recalculate-all-scores` | POST | User JWT (Bearer) |  | Get user's subaccount_id for proper isolation |
| `recompute-agent-profile` | `…/functions/v1/recompute-agent-profile` | POST | User JWT (Bearer) |  | Recomputes agent_ai_profiles for one user (on-demand) or all users (cron) |
| `reconcile-seats` | `…/functions/v1/reconcile-seats` | POST | User JWT (Bearer) |  | ─── AUTH: cron secret or service role ─── |
| `record-call` | `…/functions/v1/record-call` | POST | User JWT (Bearer) |  | Get authorization header |
| `recover-missed-onboarding` | `…/functions/v1/recover-missed-onboarding` | POST | User JWT (Bearer) | ✓ | Auth: accept anon key (from cron), cron secret header, or service role pg_cron calls with anon key Bearer token which passes Supabase gateway auth |
| `refresh-oauth-tokens` | `…/functions/v1/refresh-oauth-tokens` | POST | User JWT (Bearer) |  | Check if token needs encryption by trying to decrypt it Returns true if token needs to be encrypted (is plaintext or encrypted with wrong key) |
| `render-website` | `…/functions/v1/render-website` | POST | User JWT (Bearer) |  | Public website renderer (verify_jwt = false). Resolves the incoming custom-domain host (X-Forwarded-Host, set by the Cloudflare |
| `repair-el-inbound-webhook` | `…/functions/v1/repair-el-inbound-webhook` | POST | User JWT (Bearer) |  | repair-el-inbound-webhook — RETIRED. Returns 410 Gone. Was a one-off repair that rewrote a Twilio number's VoiceUrl and |
| `report-export` | `…/functions/v1/report-export` | POST | User JWT (Bearer) |  | report-export — robust server-side CSV export for the Custom Report Builder. The browser sends a fully-resolved ExportPlan (see src/lib/reportExport.ts); |
| `resolve-zip-counties` | `…/functions/v1/resolve-zip-counties` | POST | User JWT (Bearer) |  | ZIP -> counties, from the CMS marketplace API. WHY THIS EXISTS. Correcting IA Agency's county data needs an authoritative ZIP -> county |
| `resume-scheduled-workflows` | `…/functions/v1/resume-scheduled-workflows` | POST | User JWT (Bearer) |  | resume-scheduled-workflows Background cron job that: |
| `retireflo-intake` | `…/functions/v1/retireflo-intake` | POST | User JWT (Bearer) |  | RetireFlo survey intake → creates/updates a lead, tags Medicare or ACA. Tag-based workflows ("contact_tag_added" trigger) handle the drip. |
| `retirement-crm-automation` | `…/functions/v1/retirement-crm-automation` | POST | User JWT (Bearer) |  | Retirement Crm Automation function. |
| `retry-workflow-run` | `…/functions/v1/retry-workflow-run` | POST | User JWT (Bearer) |  | retry-workflow-run — re-queue a failed workflow execution by re-invoking trigger-workflow with the original trigger_data. Used by the support chat inline "Retry this run" action. |
| `revert-workflow-snapshot` | `…/functions/v1/revert-workflow-snapshot` | POST | User JWT (Bearer) |  | Verify the user owns the workflow (or shares its subaccount) |
| `rotate-api-key` | `…/functions/v1/rotate-api-key` | POST | User JWT (Bearer) |  | Rotate API Key Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `rotate-encryption-key` | `…/functions/v1/rotate-encryption-key` | POST | User JWT (Bearer) |  | CRITICAL SECURITY FUNCTION Rotates the OAuth encryption key by re-encrypting all tokens |
| `save-secret` | `…/functions/v1/save-secret` | POST | User JWT (Bearer) |  | Get environment variables once at the start |
| `search-knowledge-packs` | `…/functions/v1/search-knowledge-packs` | POST | User JWT (Bearer) |  | search-knowledge-packs — semantic search across platform-curated carrier knowledge. Any authenticated user can call this. Returns chunks with |
| `secure-update-role` | `…/functions/v1/secure-update-role` | POST | User JWT (Bearer) |  | SECURITY: Secure Role Update Edge Function This function handles role changes with proper authorization checks. |
| `security-audit-reminder` | `…/functions/v1/security-audit-reminder` | POST | User JWT (Bearer) |  | Security Audit Reminder Edge Function Sends quarterly reminders to admins to perform security audits |
| `seed-vault-from-env` | `…/functions/v1/seed-vault-from-env` | POST | User JWT (Bearer) |  | seed-vault-from-env One-time / repeatable admin tool to migrate secrets from the Lovable env store |
| `set-sample-listening` | `…/functions/v1/set-sample-listening` | POST | User JWT (Bearer) |  | Look up workflow for ownership/membership check |
| `setup-agent-payment-method` | `…/functions/v1/setup-agent-payment-method` | POST | User JWT (Bearer) |  | Authenticate caller |
| `setup-whitelabel-payment-method` | `…/functions/v1/setup-whitelabel-payment-method` | POST | User JWT (Bearer) |  | White-label subaccounts that support agent payment setup via the generalized page. Add future white-label client subaccount IDs here. |
| `signup-guard` | `…/functions/v1/signup-guard` | POST | User JWT (Bearer) |  | Pre-signup guard: checks IP + email against blocklists before allowing signup. Also logs every attempt to signup_attempts for monitoring + auto-rolling domain blocks. |
| `soa-create-appointment` | `…/functions/v1/soa-create-appointment` | POST | User JWT (Bearer) |  | Creates the calendar appointment for an SOA signed IN-APP (SOAForms.tsx signs both parties directly on soa_forms, so soa-public-sign never runs for it). |
| `soa-public-sign` | `…/functions/v1/soa-public-sign` | POST | User JWT (Bearer) |  | Public endpoint — no JWT required, uses token-based auth |
| `soa-send-for-signature` | `…/functions/v1/soa-send-for-signature` | POST | User JWT (Bearer) |  | Authenticate user |
| `subaccount-email-stats` | `…/functions/v1/subaccount-email-stats` | POST | User JWT (Bearer) |  | User-scoped client for data queries |
| `submit-website-lead` | `…/functions/v1/submit-website-lead` | POST | User JWT (Bearer) |  | submit-website-lead — public (verify_jwt=false) endpoint for lead_form submissions on published websites. The owning subaccount/user is resolved server-side from the |
| `summarize-conversation` | `…/functions/v1/summarize-conversation` | POST | User JWT (Bearer) |  | Format messages for the AI |
| `support-chat` | `…/functions/v1/support-chat` | POST | User JWT (Bearer) |  | Screen-specific context based on current page |
| `support-preflight-scan` | `…/functions/v1/support-preflight-scan` | POST | User JWT (Bearer) |  | Proactive pre-flight scan for the unLocked AI support widget. Returns a small array of "issues" the user almost certainly wants to know |
| `support-resolution-embed` | `…/functions/v1/support-resolution-embed` | POST | User JWT (Bearer) |  | Embeds a resolved support ticket or chat into support_resolution_kb as canonical training material for future answers. Idempotent on (source_kind, source_id). |
| `sync-ad-accounts` | `…/functions/v1/sync-ad-accounts` | POST | User JWT (Bearer) |  | Get authenticated user |
| `sync-calendar` | `…/functions/v1/sync-calendar` | POST | User JWT (Bearer) |  | TOKEN REFRESH FUNCTIONS |
| `sync-contacts` | `…/functions/v1/sync-contacts` | POST | User JWT (Bearer) |  | Create admin client for decrypting tokens |
| `sync-facebook-forms` | `…/functions/v1/sync-facebook-forms` | POST | User JWT (Bearer) |  | DEPRECATED — SCHEDULED FOR DELETION. Do not build on this function. This is the first-generation Facebook lead-form sync, superseded by `meta-forms` |
| `sync-google-contacts` | `…/functions/v1/sync-google-contacts` | POST | User JWT (Bearer) |  | Google Contacts IMPORTER (Google → CRM) Pulls *all* of the connected Google account's contacts via the People API: |
| `sync-licensing-by-npn` | `…/functions/v1/sync-licensing-by-npn` | POST | User JWT (Bearer) |  | AWS NIPR Proxy configuration |
| `sync-outlook-contacts` | `…/functions/v1/sync-outlook-contacts` | POST | User JWT (Bearer) |  | Outlook (Microsoft Graph) Contacts IMPORTER (Outlook → CRM) Mirrors `sync-google-contacts` for Microsoft 365 / Outlook.com accounts. |
| `sync-pages` | `…/functions/v1/sync-pages` | POST | User JWT (Bearer) |  | DEPRECATED for provider 'meta'. Removal checklist at the bottom of this header. This function has zero callers — it exists only as an entry in supabase/config.toml — and its |
| `sync-signup-to-ghl` | `…/functions/v1/sync-signup-to-ghl` | POST | User JWT (Bearer) |  | ── Atomic deduplication guard ──────────────────────────────────────────── claim_ghl_sync atomically sets ghl_synced=TRUE and returns TRUE only if |
| `sync-stripe-invoices` | `…/functions/v1/sync-stripe-invoices` | POST | Provider webhook signature |  | Accept subaccount_id from request body for scoped wallet lookups |
| `system-threshold-monitor` | `…/functions/v1/system-threshold-monitor` | POST | User JWT (Bearer) | ✓ | Auth: cron secret or JWT |
| `teams-meeting-create` | `…/functions/v1/teams-meeting-create` | POST | User JWT (Bearer) |  | Refresh Microsoft access token |
| `teams-meeting-delete` | `…/functions/v1/teams-meeting-delete` | POST | User JWT (Bearer) |  | Refresh Microsoft access token |
| `teams-meeting-update` | `…/functions/v1/teams-meeting-update` | POST | User JWT (Bearer) |  | Refresh Microsoft access token |
| `test-advanced-support-slack` | `…/functions/v1/test-advanced-support-slack` | POST | User JWT (Bearer) |  | Internal notification email template (to team) - Light blue branded |
| `test-cancellation-drip` | `…/functions/v1/test-cancellation-drip` | POST | User JWT (Bearer) |  | ... template helpers (same as production) |
| `test-checkout-emails` | `…/functions/v1/test-checkout-emails` | POST | User JWT (Bearer) |  | Test Checkout Emails function. |
| `test-resend-email` | `…/functions/v1/test-resend-email` | POST | User JWT (Bearer) |  | unLocked CRM branded email templates Primary blue: #4A9EFF (hsl 213 100% 68%) |
| `test-send-email` | `…/functions/v1/test-send-email` | POST | User JWT (Bearer) |  | Fallback to env variables if database settings not available |
| `tiktok-backfill-leads` | `…/functions/v1/tiktok-backfill-leads` | POST | User JWT (Bearer) |  | TikTok Historical Lead Backfill Edge Function Pulls historical leads from TikTok API for forms that may have missed webhook deliveries |
| `tiktok-forms` | `…/functions/v1/tiktok-forms` | POST | User JWT (Bearer) |  | TikTok Lead Forms Edge Function Fetches lead generation forms from TikTok Ads API |
| `tiktok-manual-token` | `…/functions/v1/tiktok-manual-token` | POST | User JWT (Bearer) |  | Get authenticated user |
| `tiktok-map-fields` | `…/functions/v1/tiktok-map-fields` | POST | User JWT (Bearer) |  | TikTok Map Fields Edge Function Saves field mappings between TikTok lead form fields and CRM fields |
| `tiktok-poll-leads` | `…/functions/v1/tiktok-poll-leads` | POST | User JWT (Bearer) |  | TikTok Poll Leads Edge Function ARCHITECTURE DOCUMENTATION (FIX 7: Internal Alignment) |
| `tiktok-refresh-tokens` | `…/functions/v1/tiktok-refresh-tokens` | POST | User JWT (Bearer) |  | TikTok Refresh Tokens Edge Function Background job to refresh expiring TikTok OAuth tokens |
| `tiktok-retry-leads` | `…/functions/v1/tiktok-retry-leads` | POST | User JWT (Bearer) |  | TikTok Retry Leads Edge Function Background job to retry failed lead processing |
| `tiktok-subscribe-webhook` | `…/functions/v1/tiktok-subscribe-webhook` | POST | Provider webhook signature |  | TikTok Subscribe Webhook Edge Function Subscribes to TikTok Lead Ads webhook notifications for forms |
| `tiktok-sync-forms` | `…/functions/v1/tiktok-sync-forms` | POST | User JWT (Bearer) |  | TikTok Sync Forms Edge Function Background job to sync ad accounts nightly |
| `tiktok-webhook` | `…/functions/v1/tiktok-webhook` | GET, HEAD, POST | Provider webhook signature |  | TikTok Webhook Edge Function Receives lead notifications from TikTok Lead Ads |
| `track-quote-open` | `…/functions/v1/track-quote-open` | POST | User JWT (Bearer) |  | Public open-tracking endpoint for quote emails. Returns a 1x1 transparent GIF and records an open event in `quote_opens`. Designed to be loaded as |
| `transcribe-agent-ai-call` | `…/functions/v1/transcribe-agent-ai-call` | POST | User JWT (Bearer) |  | Process base64 in chunks to prevent memory issues |
| `transcribe-call` | `…/functions/v1/transcribe-call` | POST | User JWT (Bearer) |  | Process base64 in chunks to prevent memory issues |
| `transcribe-voice` | `…/functions/v1/transcribe-voice` | POST | User JWT (Bearer) |  | Transcribe audio using Wispr Flow REST API Expects base64-encoded 16kHz PCM WAV audio |
| `underwriting-chat` | `…/functions/v1/underwriting-chat` | POST | User JWT (Bearer) |  | Render ITK's real carrier read as a compact, model-readable block. Kept terse so it grounds the reply without dominating the prompt. The aggregator (ITK / |
| `unenroll-contact` | `…/functions/v1/unenroll-contact` | POST | User JWT (Bearer) |  | User-invoked unenrollment of a contact from a workflow (Automation -> Enrollment). The removal logic itself already existed, but only as the `remove_from_workflow` |
| `update-auth-email` | `…/functions/v1/update-auth-email` | POST | User JWT (Bearer) |  | Verify the caller is authenticated |
| `update-wallet-settings` | `…/functions/v1/update-wallet-settings` | POST | User JWT (Bearer) |  | Authenticate user |
| `validate-phone` | `…/functions/v1/validate-phone` | POST | User JWT (Bearer) |  | Resolve who is calling, for api_usage_logs attribution. config.toml sets verify_jwt = true for this function, so a user JWT is always |
| `verify-admin-access` | `…/functions/v1/verify-admin-access` | POST | User JWT (Bearer) |  | Verify Admin Access Edge Function SECURITY: Admin-only endpoint with restricted CORS |
| `verify-mailgun-domain` | `…/functions/v1/verify-mailgun-domain` | POST | Provider webhook signature |  | NOTE: wildcard CORS (same as add-mailgun-domain). This endpoint is JWT-verified and carries no cookie credentials, so `*` is safe — and it is the only way white-label |
| `verify-recaptcha` | `…/functions/v1/verify-recaptcha` | GET, POST | User JWT (Bearer) |  | Google reCAPTCHA v2 verification + site-key delivery. Routes: |
| `webhook-emit` | `…/functions/v1/webhook-emit` | POST | Provider webhook signature | ✓ | webhook-emit — internal helper that fans out a single webhook event to all subscribed `api_webhook_subscriptions` rows for a subaccount, signs each |
| `weekly-activity-digest` | `…/functions/v1/weekly-activity-digest` | POST | User JWT (Bearer) |  | Weekly Activity Digest function. |

### Email & Notifications (71)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `gmail-send-email` | `…/functions/v1/gmail-send-email` | POST | User JWT (Bearer) |  | ENFORCEMENT: Check DND status before sending email |
| `gmail-sync` | `…/functions/v1/gmail-sync` | POST | User JWT (Bearer) |  | trigger-workflow requires a valid userId. Subaccount-scoped email_accounts rows can have a null user_id, so we validate before firing the customer_replied bridge. |
| `mailgun-stats` | `…/functions/v1/mailgun-stats` | POST | User JWT (Bearer) |  | Handle CORS preflight |
| `mailgun-webhook` | `…/functions/v1/mailgun-webhook` | POST | Provider webhook signature |  | Rate limiting map (IP -> { count, resetTime }) |
| `notify-800-number` | `…/functions/v1/notify-800-number` | POST | User JWT (Bearer) |  | Slack notifications for 800 number request lifecycle events. |
| `notify-agency-new-signup` | `…/functions/v1/notify-agency-new-signup` | POST | User JWT (Bearer) | ✓ | Agency admin emails to notify |
| `notify-agency-past-due-resolved` | `…/functions/v1/notify-agency-past-due-resolved` | POST | User JWT (Bearer) |  | Notify Agency Past Due Resolved function. |
| `notify-agency-reactivation` | `…/functions/v1/notify-agency-reactivation` | POST | User JWT (Bearer) |  | Notify Agency Reactivation function. |
| `notify-agency-upgrade` | `…/functions/v1/notify-agency-upgrade` | POST | User JWT (Bearer) |  | Agency admin emails to notify — mirrors notify-agency-new-signup |
| `notify-ai-onboarding-completed` | `…/functions/v1/notify-ai-onboarding-completed` | POST | User JWT (Bearer) |  | Notify Ai Onboarding Completed function. |
| `notify-cancellation` | `…/functions/v1/notify-cancellation` | POST | User JWT (Bearer) |  | True when this fires because the user added their goodbye note on the final step, after the cancellation was already reported. Staff still need the note, |
| `notify-lead-subscription-request` | `…/functions/v1/notify-lead-subscription-request` | POST | User JWT (Bearer) |  | Sends two emails when a user submits a lead subscription intake form: 1) Notification to agency admins with the full submission details |
| `notify-onboarding-completed` | `…/functions/v1/notify-onboarding-completed` | POST | User JWT (Bearer) |  | Best-effort display name from auth user_metadata, explicitly preferring first + last name. |
| `notify-slack-support` | `…/functions/v1/notify-slack-support` | POST | User JWT (Bearer) |  | Handle CORS preflight requests |
| `outlook-backfill-details` | `…/functions/v1/outlook-backfill-details` | POST | User JWT (Bearer) |  | One-time Outlook backfill — repair blank synced appointments. Outlook's /me/events/delta only re-emits CHANGED events, so resetting the |
| `outlook-delta-sync` | `…/functions/v1/outlook-delta-sync` | POST | User JWT (Bearer) |  | Outlook Delta Sync Edge Function Uses Microsoft Graph delta queries for robust incremental synchronization |
| `outlook-list-calendars` | `…/functions/v1/outlook-list-calendars` | POST | User JWT (Bearer) |  | Outlook List Calendars Edge Function Lists all calendars from user's Outlook account via Microsoft Graph API |
| `outlook-mail-sync` | `…/functions/v1/outlook-mail-sync` | POST | User JWT (Bearer) |  | Outlook (Microsoft Graph) Mail Sync — mirrors gmail-sync, writes to email_messages / email_threads. Invoked by frontend hook (useEmailThreads) after Outlook is connected, just like gmail-sync. |
| `outlook-refresh-token` | `…/functions/v1/outlook-refresh-token` | POST | User JWT (Bearer) |  | Outlook Refresh Token Edge Function Refreshes expired Outlook OAuth access tokens using refresh token |
| `outlook-renew-subscriptions` | `…/functions/v1/outlook-renew-subscriptions` | POST | User JWT (Bearer) |  | Outlook Renew Subscriptions Edge Function Renews Microsoft Graph webhook subscriptions before they expire |
| `outlook-save-calendar-selection` | `…/functions/v1/outlook-save-calendar-selection` | POST | User JWT (Bearer) |  | Outlook Save Calendar Selection Edge Function Saves user's selection of which Outlook calendars to sync |
| `outlook-subscribe-webhook` | `…/functions/v1/outlook-subscribe-webhook` | POST | Provider webhook signature |  | Outlook Subscribe Webhook Function Creates Microsoft Graph webhook subscriptions for calendar change notifications. |
| `outlook-webhook` | `…/functions/v1/outlook-webhook` | POST | Provider webhook signature |  | Outlook Webhook Edge Function Handles incoming webhook notifications from Microsoft Graph |
| `process-email-campaign-retries` | `…/functions/v1/process-email-campaign-retries` | POST | User JWT (Bearer) | ✓ | A throttled campaign finishes HERE, not in send-email-campaign (which skips its notification while sends are deferred) — so notify the owner |
| `process-single-email-queue` | `…/functions/v1/process-single-email-queue` | POST | User JWT (Bearer) | ✓ | Process Single Email Queue function. |
| `send-2fa-code` | `…/functions/v1/send-2fa-code` | POST | User JWT (Bearer) |  | Email 2FA Code Generator & Sender Actions: |
| `send-a2p-request-emails` | `…/functions/v1/send-a2p-request-emails` | POST | User JWT (Bearer) |  | Authenticate the user — only CRM users can submit A2P requests |
| `send-a2p-status-update` | `…/functions/v1/send-a2p-status-update` | POST | User JWT (Bearer) |  | Send A2p Status Update function. |
| `send-activation-email` | `…/functions/v1/send-activation-email` | POST | User JWT (Bearer) |  | Send Activation Email function. |
| `send-activity-summary` | `…/functions/v1/send-activity-summary` | POST | User JWT (Bearer) |  | Send Activity Summary function. |
| `send-admin-update-email` | `…/functions/v1/send-admin-update-email` | POST | User JWT (Bearer) |  | Get the update |
| `send-affiliate-payout-notification` | `…/functions/v1/send-affiliate-payout-notification` | POST | User JWT (Bearer) |  | Build payment method info if provided |
| `send-affiliate-signup-notification` | `…/functions/v1/send-affiliate-signup-notification` | POST | User JWT (Bearer) | ✓ | unLocked CRM branded affiliate signup notification email template |
| `send-appointment-reminders` | `…/functions/v1/send-appointment-reminders` | POST | User JWT (Bearer) |  | Phone normalization now handled by shared ensureE164 utility |
| `send-attribution-notification` | `…/functions/v1/send-attribution-notification` | POST | User JWT (Bearer) |  | Get user profile |
| `send-auth-email` | `…/functions/v1/send-auth-email` | POST | User JWT (Bearer) |  | Email templates for different auth actions |
| `send-booking-notification` | `…/functions/v1/send-booking-notification` | POST | User JWT (Bearer) |  | Notification settings for a booking that has no booking_link_id — Agent AI and portal bookings go straight through atomic_book_appointment and never |
| `send-build-idea` | `…/functions/v1/send-build-idea` | POST | User JWT (Bearer) |  | Send Build Idea function. |
| `send-clinic-invite` | `…/functions/v1/send-clinic-invite` | POST | User JWT (Bearer) |  | --- Ad-hoc in-memory rate limit (mirror of send-portal-invite) -------------- |
| `send-communication` | `…/functions/v1/send-communication` | POST | User JWT (Bearer) |  | Persist Gmail's thread truth immediately after a successful send, so replies can thread without waiting for gmail-sync (which may never run for all-outbound threads). |
| `send-crm-notification` | `…/functions/v1/send-crm-notification` | POST | User JWT (Bearer) |  | Placeholder token used by infoCard/ctaButton so that brandedTemplate can swap in the resolved branding.primaryColor at render-time. |
| `send-data-purchase-confirmation` | `…/functions/v1/send-data-purchase-confirmation` | POST | User JWT (Bearer) |  | Send email via Resend API |
| `send-email-campaign` | `…/functions/v1/send-email-campaign` | POST | User JWT (Bearer) |  | Attachment schema. `storagePath` points into the private `email-attachments` bucket and is read with the service-role client at send time; `url` is the |
| `send-email-reminders` | `…/functions/v1/send-email-reminders` | POST | User JWT (Bearer) |  | Automated Email Reminder Scheduler Sends email reminders at: |
| `send-feature-nudges` | `…/functions/v1/send-feature-nudges` | POST | User JWT (Bearer) |  | Weekly cron function: sends one "Have you tried X?" notification per user for features they haven't used yet. Auto-hides when they try the feature. |
| `send-feedback-email` | `…/functions/v1/send-feedback-email` | POST | User JWT (Bearer) |  | Send Feedback Email function. |
| `send-form-notification` | `…/functions/v1/send-form-notification` | POST | User JWT (Bearer) |  | Client confirmation settings |
| `send-integration-request` | `…/functions/v1/send-integration-request` | POST | User JWT (Bearer) |  | Send Integration Request function. |
| `send-invite-accepted` | `…/functions/v1/send-invite-accepted` | POST | User JWT (Bearer) |  | Get the team member details |
| `send-license-expiration-reminders` | `…/functions/v1/send-license-expiration-reminders` | POST | User JWT (Bearer) |  | ─── Helpers ──────────────────────────────────────────────────────────────── |
| `send-mailgun` | `…/functions/v1/send-mailgun` | POST | Provider webhook signature |  | MICROSOFT TOKEN REFRESH |
| `send-max-confirmation` | `…/functions/v1/send-max-confirmation` | POST | User JWT (Bearer) |  | Send Max Confirmation function. |
| `send-mention-notification` | `…/functions/v1/send-mention-notification` | POST | User JWT (Bearer) |  | Verify the caller |
| `send-new-user-notification` | `…/functions/v1/send-new-user-notification` | POST | User JWT (Bearer) |  | Authenticate the caller |
| `send-notification-test` | `…/functions/v1/send-notification-test` | POST | User JWT (Bearer) |  | Send Notification Test function. |
| `send-onboarding-email` | `…/functions/v1/send-onboarding-email` | POST | User JWT (Bearer) |  | ── Test-all path (no dedup) ────────────────────────────────────────────── |
| `send-password-reset` | `…/functions/v1/send-password-reset` | POST | User JWT (Bearer) |  | Create Supabase admin client to generate password reset link |
| `send-portal-invite` | `…/functions/v1/send-portal-invite` | POST | User JWT (Bearer) |  | --- Ad-hoc in-memory rate limit --------------------------------------------- NOTE: Backend has no shared rate-limit primitive; this is best-effort per |
| `send-pro-confirmation` | `…/functions/v1/send-pro-confirmation` | POST | User JWT (Bearer) |  | Send email via Resend API |
| `send-prospector-confirmation` | `…/functions/v1/send-prospector-confirmation` | POST | User JWT (Bearer) |  | Send email via Resend API |
| `send-quote-to-contact` | `…/functions/v1/send-quote-to-contact` | POST | User JWT (Bearer) |  | Sends a quote to a contact via email and/or SMS, with a generated PDF "Quote Summary" attachment. Logs a single combined activity to |
| `send-sms` | `…/functions/v1/send-sms` | POST | User JWT (Bearer) |  | Outbound SMS sender with Agency-Level A2P Support: - Subaccount isolation: Only uses phones owned by the sending subaccount |
| `send-smtp-email` | `…/functions/v1/send-smtp-email` | POST | User JWT (Bearer) |  | Decrypt SMTP password using the shared encryption utilities |
| `send-subaccount-invitation` | `…/functions/v1/send-subaccount-invitation` | POST | User JWT (Bearer) |  | Send via Mailgun |
| `send-support-notification` | `…/functions/v1/send-support-notification` | POST | User JWT (Bearer) |  | Support ticket notifications go ONLY to this hardcoded allow-list. Do NOT derive recipients from user_roles, workspace owners, submitters, |
| `send-system-alert` | `…/functions/v1/send-system-alert` | POST | User JWT (Bearer) |  | Handle CORS preflight |
| `send-team-invite` | `…/functions/v1/send-team-invite` | POST | User JWT (Bearer) |  | Send Team Invite Edge Function PURPOSE: |
| `send-tiktok-event` | `…/functions/v1/send-tiktok-event` | POST | User JWT (Bearer) |  | SHA-256 hash function for PII data (required by TikTok Events API) TikTok requires email and phone to be lowercase, trimmed, and SHA-256 hashed |
| `send-welcome-email` | `…/functions/v1/send-welcome-email` | POST | User JWT (Bearer) |  | Send Welcome Email function. |
| `send-whatsapp` | `…/functions/v1/send-whatsapp` | POST | User JWT (Bearer) |  | Secure Twilio WhatsApp sender with DND enforcement SECURITY: Restricted CORS + server-side subaccount validation |
| `send-whitelabel-request` | `…/functions/v1/send-whitelabel-request` | POST | User JWT (Bearer) |  | "Book a 15-minute kickoff call" CTA in the White Label confirmation email. Kept in step with the same buttons on the White Label settings page — both are |

### Integrations & Webhooks (53)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `calendly-backfill` | `…/functions/v1/calendly-backfill` | POST | Provider webhook signature |  | One-time importer: pulls the caller's existing Calendly meetings (past N months plus everything upcoming) into the appointments table. Safe to re-run: events |
| `calendly-event-types` | `…/functions/v1/calendly-event-types` | POST | Provider webhook signature |  | Get ALL Calendly connections for the subaccount (not just current user) |
| `calendly-poll-sync` | `…/functions/v1/calendly-poll-sync` | POST | Provider webhook signature | ✓ | Scheduled Calendly sync for connections that have no webhook. Calendly gates webhook subscriptions behind its Standard/Teams/Enterprise plans, so |
| `calendly-subscribe-webhook` | `…/functions/v1/calendly-subscribe-webhook` | POST | Provider webhook signature |  | Get Calendly connection |
| `calendly-webhook` | `…/functions/v1/calendly-webhook` | POST | Provider webhook signature |  | Verify Calendly webhook signature using HMAC SHA-256 |
| `comtrack-auto-sync` | `…/functions/v1/comtrack-auto-sync` | POST | Provider webhook signature |  | Commission+ Auto-Sync — scheduled background function Iterates through all active Commission+ connections with auto_sync_enabled = true |
| `comtrack-sync` | `…/functions/v1/comtrack-sync` | POST | Provider webhook signature |  | Commission+ reference endpoint. Both values were wrong and both were verified by direct request (2026-08-17): |
| `comtrack-webhook` | `…/functions/v1/comtrack-webhook` | POST | Provider webhook signature |  | Commission+ Inbound Webhook Receives push updates from Commission+ when: |
| `facebook-webhook` | `…/functions/v1/facebook-webhook` | GET, POST | User JWT (Bearer) |  | ⚠️ DEPRECATED — DO NOT USE This is the legacy single-tenant Facebook webhook handler. |
| `ghl-import-manager` | `…/functions/v1/ghl-import-manager` | POST | Provider webhook signature |  | Ghl Import Manager function. |
| `ghl-import-resume` | `…/functions/v1/ghl-import-resume` | POST | Provider webhook signature |  | Cron job: runs every 2 minutes to resume stalled/queued GHL import chunks. |
| `ghl-import-worker` | `…/functions/v1/ghl-import-worker` | POST | Provider webhook signature |  | ─── Auth: Only allow service-to-service calls ─── |
| `google-ads-attach-webhook` | `…/functions/v1/google-ads-attach-webhook` | POST | Provider webhook signature |  | Google Ads Attach Webhook function. |
| `google-ads-lead-webhook` | `…/functions/v1/google-ads-lead-webhook` | POST | Provider webhook signature |  | Constant-time key comparison to prevent timing attacks |
| `google-ads-list-accounts` | `…/functions/v1/google-ads-list-accounts` | POST | User JWT (Bearer) |  | Google Ads List Accounts function. |
| `google-ads-list-lead-forms` | `…/functions/v1/google-ads-list-lead-forms` | POST | User JWT (Bearer) |  | CRM webhook URL substring used to detect "our" webhook on a lead form |
| `google-ads-save-account` | `…/functions/v1/google-ads-save-account` | POST | User JWT (Bearer) |  | Google Ads Save Account function. |
| `google-calendar-webhook` | `…/functions/v1/google-calendar-webhook` | GET, POST | Provider webhook signature |  | Token refresh helper |
| `google-list-calendars` | `…/functions/v1/google-list-calendars` | POST | User JWT (Bearer) |  | Parse body to get subaccountId |
| `google-meet-create` | `…/functions/v1/google-meet-create` | POST | User JWT (Bearer) |  | Refresh Google access token |
| `google-renew-subscriptions` | `…/functions/v1/google-renew-subscriptions` | POST | User JWT (Bearer) |  | Renews Google Calendar push notification subscriptions before they expire Should run daily via cron to ensure continuous real-time sync |
| `google-save-calendar-selection` | `…/functions/v1/google-save-calendar-selection` | POST | User JWT (Bearer) |  | Upsert calendar selections - first delete existing for this user/provider/subaccount, then insert This handles the subaccount_id in the unique constraint properly |
| `google-sheets-action` | `…/functions/v1/google-sheets-action` | POST | User JWT (Bearer) |  | Column mappings for create/update |
| `google-sheets-get-headers` | `…/functions/v1/google-sheets-get-headers` | POST | User JWT (Bearer) |  | Get first row (headers) from the worksheet |
| `google-sheets-list-drives` | `…/functions/v1/google-sheets-list-drives` | POST | User JWT (Bearer) |  | Check if token is expired |
| `google-sheets-list-spreadsheets` | `…/functions/v1/google-sheets-list-spreadsheets` | POST | User JWT (Bearer) |  | List Google Sheets in the specified drive |
| `google-sheets-list-worksheets` | `…/functions/v1/google-sheets-list-worksheets` | POST | User JWT (Bearer) |  | Get spreadsheet metadata including worksheets |
| `google-sheets-oauth-callback` | `…/functions/v1/google-sheets-oauth-callback` | POST | User JWT (Bearer) |  | Verify HMAC signature on state |
| `google-sheets-oauth-init` | `…/functions/v1/google-sheets-oauth-init` | POST | User JWT (Bearer) |  | Get authenticated user |
| `google-subscribe-calendar` | `…/functions/v1/google-subscribe-calendar` | POST | User JWT (Bearer) |  | Token refresh helper |
| `healthsherpa-push` | `…/functions/v1/healthsherpa-push` | POST | User JWT (Bearer) |  | HealthSherpa push. Supports two products: |
| `healthsherpa-save-settings` | `…/functions/v1/healthsherpa-save-settings` | POST | User JWT (Bearer) |  | Secure endpoint for saving HealthSherpa settings (Phase 4 hardened). Secrets are stored encrypted at rest via DB trigger (pgcrypto + vault). |
| `healthsherpa-webhook` | `…/functions/v1/healthsherpa-webhook` | POST | Provider webhook signature |  | HealthSherpa inbound webhook. HealthSherpa delivers ONE event per Medicare submission, shaped |
| `meta-check-permissions` | `…/functions/v1/meta-check-permissions` | POST | Provider webhook signature |  | Capability → scope mapping comes from _shared/meta-oauth-scopes.ts so it cannot drift from what oauth-init actually asks Facebook for. |
| `meta-connections` | `…/functions/v1/meta-connections` | POST | Provider webhook signature |  | Get authenticated user |
| `meta-disconnect` | `…/functions/v1/meta-disconnect` | POST | Provider webhook signature |  | Get Meta account |
| `meta-fetch-insights` | `…/functions/v1/meta-fetch-insights` | POST | Provider webhook signature |  | Get Meta account |
| `meta-forms` | `…/functions/v1/meta-forms` | POST | Provider webhook signature |  | Parse request body for subaccountId and mode |
| `meta-map-fields` | `…/functions/v1/meta-map-fields` | POST | Provider webhook signature |  | Get user's profile to get subaccount_id |
| `meta-refresh-tokens` | `…/functions/v1/meta-refresh-tokens` | POST | Provider webhook signature | ✓ | Renews Meta long-lived user tokens before they expire (~60 days). This function was dead twice over until 2026-08-11, and that is the reason Meta customers |
| `meta-reset-permissions` | `…/functions/v1/meta-reset-permissions` | POST | Provider webhook signature |  | Explicit "Reset Facebook Page permissions" escape hatch — DELETE /me/permissions. Facebook keeps a per-app, per-Facebook-user grant of which Pages we may see, and the OAuth |
| `meta-retry-leads` | `…/functions/v1/meta-retry-leads` | POST | Provider webhook signature | ✓ | Statuses worth another attempt. 'completed' is done and 'skipped_duplicate' is a legitimate outcome rather than a failure, so neither is ever re-attempted. |
| `meta-select-page` | `…/functions/v1/meta-select-page` | POST | Provider webhook signature |  | Get Meta account |
| `meta-send-message` | `…/functions/v1/meta-send-message` | POST | Provider webhook signature |  | Get channel (includes subaccount_id for isolation) |
| `meta-subscribe-webhook` | `…/functions/v1/meta-subscribe-webhook` | POST | Provider webhook signature |  | Get Meta channel with page access token |
| `meta-sync-assets` | `…/functions/v1/meta-sync-assets` | POST | Provider webhook signature |  | Re-reads the Pages, Instagram accounts and ad accounts for a connected Meta account and refreshes the cached copies in meta_accounts / meta_channels. Backs the "Refresh Pages" |
| `meta-webhook` | `…/functions/v1/meta-webhook` | GET, POST | Provider webhook signature |  | Verify Meta webhook signature. Env var notes (canonical names): |
| `zoom-create-meeting` | `…/functions/v1/zoom-create-meeting` | POST | Provider webhook signature |  | Refresh Zoom access token |
| `zoom-delete-meeting` | `…/functions/v1/zoom-delete-meeting` | POST | Provider webhook signature |  | Refresh Zoom access token |
| `zoom-disconnect` | `…/functions/v1/zoom-disconnect` | POST | Provider webhook signature |  | Helper: return a structured failure (success: false) with secure headers. |
| `zoom-refresh-tokens` | `…/functions/v1/zoom-refresh-tokens` | POST | Provider webhook signature |  | Refresh Zoom access token |
| `zoom-update-meeting` | `…/functions/v1/zoom-update-meeting` | POST | Provider webhook signature |  | Refresh Zoom access token |
| `zoom-webhook` | `…/functions/v1/zoom-webhook` | GET, POST | Provider webhook signature |  | Decrypt OAuth token |

### Quoting & Enrollment (29)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `aca-doc-extract` | `…/functions/v1/aca-doc-extract` | POST | User JWT (Bearer) |  | aca-doc-extract — vision-based document auto-fill for ACA quoting/application. Accepts a base64 image/PDF (driver's license, pay stub, insurance card, etc.) |
| `aca-eligibility-check` | `…/functions/v1/aca-eligibility-check` | POST | User JWT (Bearer) |  | For creating new lead |
| `aca-plan-summary` | `…/functions/v1/aca-plan-summary` | POST | User JWT (Bearer) |  | Aca Plan Summary function. |
| `aca-public-quote` | `…/functions/v1/aca-public-quote` | POST | None (public) |  | Subaccount behind the public link — needed to file the quote. |
| `aca-quote` | `…/functions/v1/aca-quote` | POST | User JWT (Bearer) |  | aca-quote — AGENT marketplace quoting (verify_jwt handled in code). Authentication and response shaping only. The quote itself comes from |
| `aca-quote-ai` | `…/functions/v1/aca-quote-ai` | POST | User JWT (Bearer) |  | Aca Quote Ai function. |
| `aca-self-enroll` | `…/functions/v1/aca-self-enroll` | POST | User JWT (Bearer) |  | Where the lead came from, as a tag on the Contacts page. Keyed by the `source` written to the lead row so the two can't drift apart. |
| `compulife-quote` | `…/functions/v1/compulife-quote` | POST | User JWT (Bearer) |  | compulife-quote — Life insurance quoting via Compulife AWS proxy REQUIRED SUPABASE SECRETS (set in Dashboard → Settings → Edge Functions): |
| `csg-dvh-quote` | `…/functions/v1/csg-dvh-quote` | POST | User JWT (Bearer) |  | New API parameters |
| `csg-eapp` | `…/functions/v1/csg-eapp` | POST | User JWT (Bearer) |  | CSG E-App — enrollment application management. Docs: https://enrollmentplatform.docs.apiary.io/ (see docs/csg-eapp/SCOPING.md) |
| `csg-eapp-probe` | `…/functions/v1/csg-eapp-probe` | POST | User JWT (Bearer) |  | CSG E-App access probe — uses documented header (x-api-token) and endpoints per https://enrollmentplatform.docs.apiary.io/ |
| `csg-eapp-sync` | `…/functions/v1/csg-eapp-sync` | POST | User JWT (Bearer) | ✓ | Derive our status string from CSG's boolean flags (most-advanced wins). |
| `csg-hi-quote` | `…/functions/v1/csg-hi-quote` | POST | User JWT (Bearer) |  | In-memory fallback for same instance; primary cache is in csg_token_cache table. |
| `csg-ma-quote` | `…/functions/v1/csg-ma-quote` | POST | User JWT (Bearer) |  | Drugs the client is taking — passed to CSG as rxcui[] so per-plan tier copays populate. CSG returns concrete dollar copays for each of the 5 standard Part D tiers per plan |
| `csg-medigap-quote` | `…/functions/v1/csg-medigap-quote` | POST | User JWT (Bearer) |  | Service-role callers only: the tenant whose rate-limit budget this call spends. |
| `dvh-plan-explain` | `…/functions/v1/dvh-plan-explain` | POST | User JWT (Bearer) |  | Dvh Plan Explain function. |
| `dvh-quote-ai` | `…/functions/v1/dvh-quote-ai` | POST | User JWT (Bearer) |  | Dvh Quote Ai function. |
| `hi-quote-ai` | `…/functions/v1/hi-quote-ai` | POST | User JWT (Bearer) |  | Rate limiting |
| `ixn-quotes` | `…/functions/v1/ixn-quotes` | POST | User JWT (Bearer) |  | IXN error payloads we have seen embed: "referenceId: <uuid>" in the message. |
| `ixnQuoteTest` | `…/functions/v1/ixnQuoteTest` | POST | User JWT (Bearer) |  | Initialize Supabase for auth validation |
| `life-compulife-quote-ai` | `…/functions/v1/life-compulife-quote-ai` | POST | User JWT (Bearer) |  | Life Compulife Quote Ai function. |
| `life-public-quote` | `…/functions/v1/life-public-quote` | POST | None (public) |  | life-public-quote — PUBLIC (verify_jwt = false) Powers the consumer life quote widget at /q/:slug ("Beacon" phase 1). |
| `ma-plan-explain` | `…/functions/v1/ma-plan-explain` | POST | User JWT (Bearer) |  | A missing value means the carrier did not report it — say so explicitly, and never let downstream math treat it as $0. |
| `ma-quote-ai` | `…/functions/v1/ma-quote-ai` | POST | User JWT (Bearer) |  | Valid US state codes |
| `medigap-quote-ai` | `…/functions/v1/medigap-quote-ai` | POST | User JWT (Bearer) |  | Rate limiting |
| `private-plans-api` | `…/functions/v1/private-plans-api` | POST | User JWT (Bearer) |  | ==================== Types ==================== |
| `private-plans-quote-ai` | `…/functions/v1/private-plans-quote-ai` | POST | User JWT (Bearer) |  | Private Plans Quote Ai function. |
| `private-plans-search` | `…/functions/v1/private-plans-search` | POST | User JWT (Bearer) |  | ==================== Types ==================== |
| `quote-ai` | `…/functions/v1/quote-ai` | POST | User JWT (Bearer) |  | RATE LIMITING - In-memory fast check |

### Telephony & Messaging (31)

| Function | Path | Methods | Auth | Cron | Description |
|---|---|---|---|---|---|
| `a2p-auto-approve` | `…/functions/v1/a2p-auto-approve` | POST | User JWT (Bearer) |  | A2p Auto Approve function. |
| `a2p-register` | `…/functions/v1/a2p-register` | POST | User JWT (Bearer) |  | Helper to make Twilio API calls |
| `make-voice-call` | `…/functions/v1/make-voice-call` | POST | User JWT (Bearer) |  | Outbound Voice Call with GHL-style features: - DND check before calling |
| `phone-system-alerts` | `…/functions/v1/phone-system-alerts` | POST | User JWT (Bearer) | ✓ | Agency admin emails to notify |
| `twilio-a2p-registration` | `…/functions/v1/twilio-a2p-registration` | POST | Provider webhook signature |  | Get authenticated user |
| `twilio-call-queue` | `…/functions/v1/twilio-call-queue` | POST | Provider webhook signature |  | Twilio Call Queue Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed queue requests. |
| `twilio-caller-id` | `…/functions/v1/twilio-caller-id` | POST | User JWT (Bearer) |  | Initialize Supabase with user's auth |
| `twilio-campaign-chime` | `…/functions/v1/twilio-campaign-chime` | POST | Provider webhook signature |  | Validate Twilio signature |
| `twilio-conference-manage` | `…/functions/v1/twilio-conference-manage` | POST | Provider webhook signature |  | Create a conference record in the database. The actual Twilio Conference is created when the first participant joins via TwiML. |
| `twilio-conference-status` | `…/functions/v1/twilio-conference-status` | POST | Provider webhook signature |  | Terminal call_conferences statuses that must never be revived or overwritten. |
| `twilio-dial-complete` | `…/functions/v1/twilio-dial-complete` | POST | Provider webhook signature |  | Twilio <Dial> action handler — terminates the parent call when the browser <Client> leg ends. |
| `twilio-end-call` | `…/functions/v1/twilio-end-call` | POST | User JWT (Bearer) |  | End/Hang-up a Twilio Call Uses Twilio's Update Call API to terminate an in-progress call. |
| `twilio-hold-call` | `…/functions/v1/twilio-hold-call` | POST | User JWT (Bearer) |  | Hold music options |
| `twilio-inbound-sms` | `…/functions/v1/twilio-inbound-sms` | POST | Provider webhook signature |  | Twilio Inbound SMS Webhook Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed inbound messages. |
| `twilio-incoming-call` | `…/functions/v1/twilio-incoming-call` | POST | Provider webhook signature |  | Twilio Incoming Call Webhook Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed webhook attacks. |
| `twilio-phone-numbers` | `…/functions/v1/twilio-phone-numbers` | POST | Provider webhook signature |  | Twilio Phone Number Management Handles search, purchase (with correct webhook configuration), and release |
| `twilio-ring-group` | `…/functions/v1/twilio-ring-group` | POST | Provider webhook signature |  | Twilio Ring Group Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed routing requests. |
| `twilio-sms-status` | `…/functions/v1/twilio-sms-status` | POST | Provider webhook signature |  | Twilio SMS Status Webhook Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed status updates. |
| `twilio-transfer-call` | `…/functions/v1/twilio-transfer-call` | POST | Provider webhook signature |  | Twilio Transfer Call function. |
| `twilio-trusthub-callback` | `…/functions/v1/twilio-trusthub-callback` | POST | Provider webhook signature |  | Initialize Supabase client |
| `twilio-voice-app-status` | `…/functions/v1/twilio-voice-app-status` | POST | User JWT (Bearer) |  | This endpoint is safe to be auth-protected so it can't be used as a Twilio probe. |
| `twilio-voice-status` | `…/functions/v1/twilio-voice-status` | POST | Provider webhook signature |  | Twilio Voice Status Webhook Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed status callbacks. |
| `twilio-voice-token` | `…/functions/v1/twilio-voice-token` | POST | Provider webhook signature |  | Generate Twilio Access Token for browser-based calling Manual JWT creation following Twilio's exact specification |
| `twilio-voice-twiml` | `…/functions/v1/twilio-voice-twiml` | POST | Provider webhook signature |  | TwiML endpoint for browser-based voice calls (Twilio Client SDK) SECURITY: Validates X-Twilio-Signature to prevent spoofed requests |
| `twilio-voicemail` | `…/functions/v1/twilio-voicemail` | POST | Provider webhook signature |  | Twilio Voicemail Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed voicemail requests. |
| `twilio-voicemail-complete` | `…/functions/v1/twilio-voicemail-complete` | POST | Provider webhook signature |  | Twilio Voicemail Complete Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed recording callbacks. |
| `twilio-voicemail-drop` | `…/functions/v1/twilio-voicemail-drop` | POST | Provider webhook signature |  | Resolve CORS headers per-request so the preview, app.unlockedcrm.ai, and crm.awakeningfg.com origins all work (not just the first allowed origin). |
| `twilio-voicemail-transcription` | `…/functions/v1/twilio-voicemail-transcription` | POST | Provider webhook signature |  | Twilio Voicemail Transcription Handler Called by Twilio when voicemail transcription is complete. |
| `twilio-whisper` | `…/functions/v1/twilio-whisper` | POST | Provider webhook signature |  | Twilio Whisper Handler - Press 1 to Accept SECURITY: Validates X-Twilio-Signature to prevent spoofed whisper requests. |
| `twilio-whisper-result` | `…/functions/v1/twilio-whisper-result` | POST | Provider webhook signature |  | Twilio Whisper Result Handler SECURITY: Validates X-Twilio-Signature to prevent spoofed DTMF results. |
| `voicemail-proxy` | `…/functions/v1/voicemail-proxy` | HEAD, POST | User JWT (Bearer) |  | Voicemail Proxy - Serves voicemail audio files with correct Content-Type headers This edge function proxies audio files from Supabase Storage, ensuring |

## Conventions & limits

- **Invocation:** the app calls functions via `supabase.functions.invoke('<name>', { body })` — always an HTTPS `POST` with a JSON body to `https://gzigyepfasiumngxilai.supabase.co/functions/v1/<name>`.
- **Rate limit:** 100 req/min per key on the Public API. Internal functions are not publicly rate-limited but enforce auth.
- **CORS:** functions answer `OPTIONS` preflights; browser-facing functions use a whitelist of app origins.
- **Errors:** `400` validation, `401` missing/invalid credentials, `403` permission denied, `404` not found, `429` rate limited (Public API), `500` internal.
- **Counts:** 538 edge functions total; 35 cron-triggered; 85 webhook receivers; 1 public REST endpoint (`/public-api`) with 4 methods.
