API Reference

Complete reference for all ChatbotSaaS API endpoints. The base URL is your app domain — e.g. https://yourapp.com.

Authentication

API Key

Pass your sk_live_... key in the Authorization: Bearer header.

Admin

Pass ADMIN_SECRET in the Authorization: Bearer header.

Cron Secret

Pass CRON_SECRET in the Authorization: Bearer header. Set by Vercel Cron.

Core

1 endpoint
GET/api/healthPublicedge

System health check. Returns KV connectivity, env-var status, and a ready_to_sell boolean. Missing env var names are only revealed to authenticated admins.

Response
{ status, ready_to_sell, version, response_ms, checks: { kv, env_vars } }

Chat

2 endpoints
POST/api/chatAPI Keyedge

20-step chat hot path. Injection detection → auth → domain check → rate limit → status/usage checks → FAQ cache → RAG → AI completion → tool calls (lead capture / escalation) → conversation save → analytics.

Request Body
{ message: string, conversationId?: string, sessionId?: string, metadata?: { url, userAgent } }
Response
{ reply, conversationId, intent, sentiment, followUpQuestions, leadCaptured, escalated, model, usage }
POST/api/demoPublicedge

Live demo endpoint (no API key). Supports 4 built-in business personas (SaaS, Ecommerce, Healthcare, Legal). Rate-limited to 30 req/min per IP.

Request Body
{ message: string, business: "saas" | "ecommerce" | "healthcare" | "legal", conversationId?: string }
Response
{ reply, conversationId, followUpQuestions, business }

Widget

2 endpoints
POST/api/widget-tokenAPI Keynode

Exchange a raw API key for a short-lived (1hr) widget token. Use this so the raw key is never embedded in HTML.

Request Body
{}
Response
{ token: string, expiresAt: number }
GET/api/widget-tokenPublicnode

Resolve a widget token to a hashed key for server-side use.

Response
{ hashedKey: string }

Client (Self-Service)

7 endpoints
GET/api/client/accountAPI Keynode

Account overview including status, plan, trial end date, monthly usage, and lead/conversation counts.

Response
{ client, usage, leadsCount, conversationsCount }
GET/api/client/leadsAPI Keynode

Paginated list of captured leads with name, email, phone, company, intent, and timestamp.

Response
{ leads: Lead[], count: number }
GET/api/client/conversationsAPI Keynode

Last 30 conversations with message history, intent, sentiment, and lead/escalation flags.

Response
{ conversations: Conversation[] }
GET/api/client/kbAPI Keynode

List knowledge base chunks for this client. Pro+ plan required.

Response
{ chunks: string[], count: number }
POST/api/client/kbAPI Keynode

Add knowledge to the RAG vector index. Accepts a URL to scrape (up to 10 pages) or raw text. Pro+ plan required.

Request Body
{ type: "url" | "text", content: string }
Response
{ chunks: number, message: string }
POST/api/client/upgradeAPI Keynode

Initiate a PayPal subscription upgrade. Returns a PayPal approval URL to redirect the user to.

Request Body
{ plan: "starter" | "pro" | "enterprise", billingPeriod: "monthly" | "annual" }
Response
{ approvalUrl: string, subscriptionId: string }
POST/api/client/cancelAPI Keynode

Cancel the active PayPal subscription. Requires { confirm: true } in body as a safety guard.

Request Body
{ confirm: true }
Response
{ cancelled: true, status: "cancelled" }

Billing

3 endpoints
GET/api/billing/returnPublicnode

PayPal return URL after user approves a subscription. Verifies the subscription_id matches the pending record stored for this client (prevents account takeover), then activates the account.

Response
Redirect to /client-dashboard?upgrade=success or ?upgrade=error
POST/api/webhooks/paypalPublicnode

PayPal webhook receiver. Verifies PAYPAL-TRANSMISSION-SIG and processes 11 event types (ACTIVATED, RENEWED, CANCELLED, EXPIRED, SUSPENDED, PAYMENT.SALE.*, PAYMENT.FAILED, UPDATED). Idempotent via NX KV set.

Response
{ received: true }
POST/api/webhooks/shopifyPublicnode

Shopify webhook receiver. Verifies HMAC-SHA256 signature per client, stores last 100 events. Client identified by ?client= query param.

Request Body
Shopify webhook payload
Response
{ received: true }

Admin

14 endpoints
GET/api/admin/clientsAdminnode

List all clients with config, usage, and lead counts. Sensitive fields (hubspotApiKey, shopifyWebhookSecret) are redacted.

Response
{ clients: ClientConfig[], count: number }
POST/api/admin/clientsAdminnode

Create a new client. Generates an API key (sk_live_... prefix), stores only the HMAC-SHA256 hash. The raw key is returned once and never stored.

Request Body
{ businessName, email, domain, plan, module, widgetTitle?, widgetColor? }
Response
{ apiKey: string (returned once), hashedKey, client }
GET/api/admin/clients/[hashedKey]Adminnode

Get a single client by hashed key.

Response
ClientConfig (secrets redacted)
PATCH/api/admin/clients/[hashedKey]Adminnode

Update client config or run a special action: toggle_active, rotate_key (copies all KV data to new prefix), force_plan, extend_trial.

Request Body
{ action?: "toggle_active"|"rotate_key"|"force_plan"|"extend_trial", ...fields }
Response
Varies by action
DELETE/api/admin/clients/[hashedKey]Adminnode

GDPR erasure. Cancels PayPal subscription, deletes vector KB, and removes all 30+ KV key patterns for this client.

Response
{ deleted: true, hashedKey }
GET/api/admin/analyticsAdminnode

Aggregated analytics for a client over 30 or 90 days: totals, daily breakdown, top intents, top sentiments.

Response
AggregatedAnalytics
GET/api/admin/billingAdminnode

Billing ledger for a client (last 50 events).

Response
{ ledger: BillingEvent[] }
PATCH/api/admin/billingAdminnode

Force a plan change on a client.

Request Body
{ client: hashedKey, plan: PlanId }
Response
{ updated: true }
POST/api/admin/broadcastAdminnode

Send a broadcast email to Active, Paid, Trial, or All clients. Supports {{business_name}} substitution and dry-run mode.

Request Body
{ subject, body, audience: "active"|"paid"|"trial"|"all", dryRun?: boolean }
Response
{ queued: number, dryRun: boolean, recipients?: string[] }
GET/api/admin/logsAdminnode

Search logs. Type: audit (last 100 audit entries), errors (last 100 errors), gdpr_export (full JSON export for one client).

Response
AuditEntry[] | ErrorEntry[] | GDPR JSON
GET/api/admin/leadsAdminnode

All leads across all clients, or filtered to one client. Supports CSV export via ?format=csv.

Response
{ leads: Lead[] } or CSV file
GET/api/admin/kbAdminnode

List knowledge base chunks for a client.

Response
{ chunks: string[], count: number }
POST/api/admin/kbAdminnode

Add knowledge (URL scrape up to 10 pages, or raw text) to a client's RAG vector index.

Request Body
{ client: hashedKey, type: "url"|"text", content: string }
Response
{ chunks: number, message: string }
DELETE/api/admin/kbAdminnode

Delete all knowledge base vectors for a client.

Response
{ deleted: true }

Cron Jobs

2 endpoints
POST/api/cron/daily-syncCron Secretnode

Runs at 06:00 UTC daily. Scans all active clients: expires trials, repairs PayPal status drift, detects fast-cancel fraud (subscription cancelled < 48h after activation).

Response
{ processed: number, errors: number }
POST/api/cron/email-queueCron Secretnode

Runs hourly. Drains the email queue — up to 100 emails per run with a 1.1s delay between sends (Resend rate limit compliance). 3 retries per message.

Response
{ sent: number, failed: number }

Analytics (Client)

1 endpoint
GET/api/client/accountAPI Keynode

Includes current-month usage count (hincrby per-day analytics), lead count, and conversation count.

Response
{ client, usage, leadsCount, conversationsCount }

Webhooks

2 endpoints
POST/api/webhooks/paypalPublicnode

PayPal sends webhook events here. Signature verified with PAYPAL_WEBHOOK_ID. Events processed: BILLING.SUBSCRIPTION.ACTIVATED/RENEWED/CANCELLED/EXPIRED/SUSPENDED/UPDATED, PAYMENT.SALE.COMPLETED/DENIED/REFUNDED, PAYMENT.FAILED.

Request Body
PayPal webhook payload
Response
{ received: true }
POST/api/webhooks/shopifyPublicnode

Shopify sends webhook events here. HMAC-SHA256 verified per client using shopifyWebhookSecret. Stores last 100 events per client.

Request Body
Shopify webhook payload
Response
{ received: true }

Rate Limits

Pro
60 req/min per key
10,000 chats/mo

All endpoints also share a global per-IP limit of 30 req/min. Rate-limited responses return HTTP 429 with a retryAfter timestamp.

Error Codes

StatusMeaningExample
400Bad request / injection blockedInvalid JSON, injection detected
401UnauthorizedMissing or invalid API key
402Payment requiredTrial expired or subscription lapsed
403ForbiddenDomain not on allowlist, account suspended
404Not foundClient or resource does not exist
429Rate limit / usage capPer-minute key limit, monthly chat cap
500Server errorUnexpected error (check /api/health)
503Service unavailableAI or KV temporarily unavailable