Reference

API reference

The Voxa HTTP API powers the dashboard, the onboarding wizard, and the n8n orchestration backbone. All endpoints accept and return JSON unless otherwise noted.

Authentication

Auth was removed from this build — every request is treated as the same demo user (demo-user / demo@voxa.local). To wire Clerk back in, restore middleware.ts to useclerkMiddleware and replace lib/auth.ts's stub with the real @clerk/nextjs/server imports.

Internal endpoints called by n8n (/api/agent/create, the webhook handlers) verify a shared secret via X-Voxa-Internal-Secret, read from VOXA_INTERNAL_SECRET.

Errors

Voxa uses standard HTTP status codes. Successful responses are 2xx; client errors are 4xx; server errors are 5xx. Error bodies always have an error string and may include a issues field with Zod validation details.

error.jsonjson
{
  "error": "Invalid request body",
  "issues": {
    "fieldErrors": {
      "tier": ["Invalid enum value. Expected 'starter' | 'growth' | 'scale'"]
    }
  }
}

Rate limits

No application-level rate limits are enforced. Upstream providers do rate-limit independently — most notably the Twilio WhatsApp Sandbox (50 msg/day) and the ElevenLabs Conv AI tool timeout (~5s per webhook).

Idempotency

Stripe webhook deliveries are deduplicated by event.id in the stripe_webhook_events table. Stripe Meter Events use a derived identifier ({conversation_id}_meter) so retried meter writes never double-bill.

Health

GET/api/health

Liveness check. Returns a JSON envelope with the current server time.

curl http://localhost:4321/api/health

Voice clone

POST/api/voice/clone

Upload a 60-second audio sample. Voxa creates an ElevenLabs Instant Voice Clone and attaches the resulting voice_id to the caller's primary agent.

Body (multipart/form-data)

audioFilerequired

Audio blob. Max 10 MB. WebM, MP3, WAV, M4A are all accepted. Voxa converts everything to 22050 Hz mono before upload.

Response

voiceIdstringrequired

ElevenLabs voice ID. Stored on the agents row.

namestringrequired

Display name, derived from the demo user ID.

curl -X POST http://localhost:4321/api/voice/clone \
  -F "audio=@./sample-60s.webm"

Knowledge ingest

POST/api/knowledge/ingest

Ingest a public URL into the agent's knowledge base. The agent's get_business_info tool can answer questions about the page from that point on.

urlstringrequired

Public HTTPS URL. JS-rendered pages may need an extra crawl pass before the content is queryable (handled by EL).

Agent create

POST/api/agent/create

Internal endpoint called by n8n W1 during onboarding. Creates the ElevenLabs Conv AI agent with the canonical multilingual system prompt + the 6 webhook tools.

Internal — requires shared secret

Caller must send X-Voxa-Internal-Secret: $VOXA_INTERNAL_SECRET. The dashboard never calls this directly; n8n W1 owns it.
business_iduuidrequired

Foreign key into businesses. The agent inherits the business name, language, and voiceId.

Onboarding status

GET/api/onboarding/status

Used by the provisioning step of the wizard to poll progress. Returns 0–6 inclusive.

completedStepsnumber (0–6)required

Derived from the agents row state: voice cloned, agent created, number purchased, number imported, status=active.

status'provisioning' | 'active' | 'failed'required

Mirror of agents.status.

phoneNumberstring | nulloptional

E.164 number assigned to the agent, once active.

Stripe checkout

POST/api/stripe/checkout

Create a Stripe Checkout session with both the flat licensed price and the metered price for the chosen tier.

tier'starter' | 'growth' | 'scale'required

Which Voxa plan to subscribe to.

curl -X POST http://localhost:4321/api/stripe/checkout \
  -H 'Content-Type: application/json' \
  -d '{"tier": "growth"}'

Stripe portal

POST/api/stripe/portal

Returns a one-time URL into the Stripe Customer Portal so the owner can update payment method, view invoices, or cancel.

No body

The portal endpoint reads the subscription row attached to the current business. If no subscription exists, it returns 404.

Onboarding business

POST/api/onboarding/business

Persist the form values from step 2 of the onboarding wizard.

Onboarding scrape

POST/api/onboarding/scrape

Convenience wrapper for the website-URL step that forwards into /api/knowledge/ingest.