Dispo Email Review API
Express sub-router that serves the backend for the HubSpot UI Extension (DispoEmails card) and the Lovable backup interface. Manages the dispo email approval queue — listing, previewing, approving, skipping, and bulk-approving queued emails for deal pipelines. Also serves CRMLS pipeline progress and the verification modal for gate-approval workflows. Mounted inside hubspot-handler.js at base path /webhook/hubspot/api/dispo.
Endpoint
| Method | Path | Description |
|---|---|---|
GET | /webhook/hubspot/api/dispo/emails?dealId=X | List queued emails for a deal |
POST | /webhook/hubspot/api/dispo/approve | Approve + send a queued email |
POST | /webhook/hubspot/api/dispo/skip | Mark email as skipped |
GET | /webhook/hubspot/api/dispo/preview/:id | Rendered HTML preview (for iframe) |
POST | /webhook/hubspot/api/dispo/approve-all | Bulk approve all pending for a deal |
GET | /webhook/hubspot/api/dispo/:dealId/pipeline | CRMLS pipeline progress JSON |
GET | /webhook/hubspot/api/dispo/screenshot/:dealId | Map screenshot PNG |
POST | /webhook/hubspot/api/dispo/:dealId/pipeline-verify | Write gate file (approved/rejected) |
GET | /webhook/hubspot/api/dispo/:dealId/pipeline-ui | Verification HTML page (iframe modal) |
Port: 18790 (sub-router on hubspot-handler.js, same Express app)
Registered FUNNEL path: https://webhook.reri.co/webhook/hubspot/api/dispo (approved in FUNNEL-REGISTRY)
Auth method
Inherits HubSpot HMAC verification from the parent hubspot-handler.js Express application — no separate auth layer in this router. CORS is configured for HubSpot UI Extensions:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, OPTIONS
OPTIONS preflight requests return 200 OK immediately.
Payload shape
GET /emails — query param dealId required.
POST /approve:
{ "emailId": "uuid", "dealId": "string" }POST /approve-all:
{ "dealId": "string" }POST /:dealId/pipeline-verify:
{ "status": "approved" | "rejected" }Downstream dispatch
dispo-api.js (sub-router)
├─ GET /emails → supabase.from('dispo_email_queue').select() filtered by dealId
├─ POST /approve → dispo-email-sender.js (sendQueued) + Discord notify
├─ POST /skip → supabase update (status='skipped') + Discord notify
├─ GET /preview/:id → fetch template HTML → return rendered preview
├─ POST /approve-all → bulk loop over pending → sendQueued() for each
├─ GET /:dealId/pipeline → CRMLS pipeline progress query → JSON response
├─ GET /screenshot/:dealId → serve PNG from data/screenshots/
├─ POST /:dealId/pipeline-verify → write gate file (approved/rejected) to filesystem
└─ GET /:dealId/pipeline-ui → serve verification HTML page
Supabase table: dispo_email_queue (state tracking for queued emails)
Discord channel: #dispo (channel ID 1473827948791463936) via DiscordWebhookSender
Dedup strategy
State managed via dispo_email_queue Supabase table. Approved/skipped emails have status updated — subsequent approve calls on the same emailId are idempotent (upsert/status check). Pipeline-verify gate file writes are idempotent (file overwrite).
Audit trail
- Logger:
logtaggeddispo-apiviascripts/lib/logger.js. - Discord: Approval/skip actions trigger notifications to
#dispochannel for real-time visibility. - Supabase: All queue state transitions persisted in
dispo_email_queuerows. - Gate files:
pipeline-verifywrites to local filesystem as a gate artifact for the verification modal flow.
Related
- webhook-architecture — This is a sub-router; auth and dedup governance apply from parent
hubspot-handler.js - hubspot — HubSpot UI Extension (DispoEmails card) calls these endpoints; parent handler HMAC applies
- _summary — BetterFiles TC workflow uses this API to manage dispo email queue and CRMLS pipeline gates
- _summary — Acquisition deals move through dispo pipeline tracked here