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": "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
/api/healthLiveness check. Returns a JSON envelope with the current server time.
curl http://localhost:4321/api/healthVoice clone
/api/voice/cloneUpload 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)
audioFilerequiredAudio blob. Max 10 MB. WebM, MP3, WAV, M4A are all accepted. Voxa converts everything to 22050 Hz mono before upload.
Response
voiceIdstringrequiredElevenLabs voice ID. Stored on the agents row.
namestringrequiredDisplay name, derived from the demo user ID.
curl -X POST http://localhost:4321/api/voice/clone \
-F "audio=@./sample-60s.webm"Knowledge ingest
/api/knowledge/ingestIngest 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.
urlstringrequiredPublic HTTPS URL. JS-rendered pages may need an extra crawl pass before the content is queryable (handled by EL).
Agent create
/api/agent/createInternal 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
X-Voxa-Internal-Secret: $VOXA_INTERNAL_SECRET. The dashboard never calls this directly; n8n W1 owns it.business_iduuidrequiredForeign key into businesses. The agent inherits the business name, language, and voiceId.
Onboarding status
/api/onboarding/statusUsed by the provisioning step of the wizard to poll progress. Returns 0–6 inclusive.
completedStepsnumber (0–6)requiredDerived from the agents row state: voice cloned, agent created, number purchased, number imported, status=active.
status'provisioning' | 'active' | 'failed'requiredMirror of agents.status.
phoneNumberstring | nulloptionalE.164 number assigned to the agent, once active.
Stripe checkout
/api/stripe/checkoutCreate a Stripe Checkout session with both the flat licensed price and the metered price for the chosen tier.
tier'starter' | 'growth' | 'scale'requiredWhich Voxa plan to subscribe to.
curl -X POST http://localhost:4321/api/stripe/checkout \
-H 'Content-Type: application/json' \
-d '{"tier": "growth"}'Stripe portal
/api/stripe/portalReturns a one-time URL into the Stripe Customer Portal so the owner can update payment method, view invoices, or cancel.
No body
404.Onboarding business
/api/onboarding/businessPersist the form values from step 2 of the onboarding wizard.
Onboarding scrape
/api/onboarding/scrapeConvenience wrapper for the website-URL step that forwards into /api/knowledge/ingest.