All REST endpoints grouped by security scheme, with request/response shapes and the SSE streaming protocol for chat.
The API uses four distinct authentication methods depending on the caller.
Auth0-issued RS256 JWT with JWKS validation. Custom claims at https://ambasdr.com/user_id and https://ambasdr.com/role. Used by all /v1/* protected routes. Header: Authorization: Bearer <token>.
Shared secret for machine-to-machine communication. Used only by POST /internal/users/provision. Header: Authorization: Bearer <M2M_SECRET>.
Shared secret for the LiveKit agent's backend calls. Used by all /v1/agent/* routes. Header: X-API-Key: <AGENT_API_KEY>.
Bearer JWT is accepted but not required on POST /v1/pages/:page_id/room-token. If present, the caller is identified as the page owner. If absent, the caller is treated as a visitor.
No authentication required. These endpoints serve the public-facing page and chat experience.
| Endpoint | Description |
|---|---|
GET /v1/public/pages/:slug |
Returns full public page data: page info (slug, title, description, user_types), user profile (display_name, avatar_url, bio), social_links array, theme settings, and agent config (agent_name, greeting_message). |
POST /v1/public/pages/:slug/chat |
Streams an AI chat response via SSE. Body: {"message": "...", "thread_id": "optional-uuid"}. Returns event stream (see SSE Protocol section). |
Bearer JWT required. Manage the authenticated user's profile. All three endpoints share the same identity-resolution chain — see Architecture §10 (Authentication and User Identity Resolution) for the full lookup priority.
| Endpoint | Description |
|---|---|
GET /v1/me |
Returns the authenticated user's profile. Also updates last_login_at. Lazily provisions the user row if the JWT carries a valid sub claim but no Ambasdr user row exists yet — never 404 on a token-valid caller. |
PUT /v1/me |
Update profile fields. Body: {"display_name": "...", "avatar_url": "...", "bio": "..."}. All fields optional. Lazy-provisions the user the same way GET does, then applies the update. |
DELETE /v1/me |
Soft-delete the user account. Sets deleted_at timestamp. Subsequent authenticated calls with the same Auth0 sub return 404 user account has been deleted — the lazy-provisioning chain detects soft-deleted rows and refuses to re-create. |
Bearer JWT required. Single-submission endpoint that creates the user's page, uploads documents, and triggers agent instruction generation.
| Endpoint | Description |
|---|---|
POST /v1/onboarding |
Multipart form. Fields: first_name, last_name, slug, user_types (JSON), descriptor, agent_system_prompt, agent_focus, social_links (JSON), custom_links (JSON), document_contexts (JSON). Files: profile_image, documents[]. Returns: {"page_id": "uuid", "page_slug": "slug"}. |
GET /v1/availability?slug=X |
Check if a slug is available. Returns: {"available": true|false}. Validates format (lowercase, alphanumeric, hyphens) and checks uniqueness. |
The service checks for double-submission before creating any records. If the user already has a page, the endpoint returns the existing page ID. After a successful submission, an async goroutine generates personalized agent instructions in the background.
Bearer JWT required. CRUD operations on the user's pages. Ownership is verified on all operations.
| Endpoint | Description |
|---|---|
POST /v1/pages |
Create a page. Auto-generates slug from title if not provided. Creates default theme and agent config in a transaction. |
GET /v1/pages |
List all pages for the authenticated user, ordered by created_at DESC. |
GET /v1/pages/:page_id |
Get a single page. Requires ownership. |
PUT /v1/pages/:page_id |
Update page. Slug changes enforced with a 30-day cooldown via slug_changed_at. Validates persona metadata. |
DELETE /v1/pages/:page_id |
Soft-delete. Cascades to theme, agent config, documents, and chat threads. |
Bearer JWT required. Upload and manage knowledge base files attached to a page. Max 2 documents per page, 2MB per file.
| Endpoint | Description |
|---|---|
POST /v1/pages/:page_id/documents |
Upload a document. Multipart form with file and optional context_text. Validates MIME type (PDF, TXT, MD, CSV, DOCX), size (2MB), and count limit (2). Stores in S3-compatible storage. |
GET /v1/pages/:page_id/documents |
List all documents for the page, ordered by created_at DESC. |
GET /v1/pages/:page_id/documents/:doc_id |
Get a single document. Verifies it belongs to the specified page. |
PATCH /v1/pages/:page_id/documents/:doc_id |
Update metadata. Body: {"context_text": "...", "visibility": "public|private", "is_published": true|false}. |
DELETE /v1/pages/:page_id/documents/:doc_id |
Soft-delete from database and remove file from object storage. |
Bearer JWT required. Manage social and custom links displayed on the public page.
| Endpoint | Description |
|---|---|
GET /v1/pages/:page_id/social-links |
List all social links for the page, ordered by display_order. |
PUT /v1/pages/:page_id/social-links |
Replace all social links (PUT semantics). Body: array of {"platform": "instagram", "label": "...", "url": "..."}. Platforms: instagram, facebook, linkedin, tiktok, threads, youtube, custom. |
Bearer JWT required. Configure the AI agent's behavior for a page.
| Endpoint | Description |
|---|---|
GET /v1/pages/:page_id/agent-config |
Get the agent config. Includes generation_status for polling during async instruction generation. |
PATCH /v1/pages/:page_id/agent-config |
Partial update. Fields: agent_name, greeting_message, system_prompt, personality_traits (array), model, temperature, max_tokens, focus. All optional. |
API Key required (X-API-Key header). Used by the Python LiveKit agent to interact with the backend.
| Endpoint | Description |
|---|---|
GET /v1/agent/sessions/:page_id/config |
Full session config: agent_name, greeting_message, system_prompt, personality_traits, model, temperature, max_tokens, page_title, page_description, documents, social_links. |
GET /v1/agent/sessions/:page_id/voice-prompt |
Voice-specific bootstrap payload — fully composed system prompt (personalization + operating contract + KG context block), agent_name, the greeting line, full greetings_pool, model / temperature / max_tokens, and observability counters (nodes / edges loaded). Called once at session start by the LiveKit agent. |
POST /v1/agent/chat/stream |
Stream a chat response. Body: {"page_id": "...", "turn_id": "...", "messages": [{"role": "user", "content": "..."}]}. Returns SSE stream. |
POST /v1/agent/chat |
Non-streaming chat fallback. Same body shape, returns complete response. |
POST /v1/agent/sessions/:page_id/turns |
Append a single voice-conversation turn (user or assistant) to the persistent chat thread. The voice agent calls this after each STT/TTS exchange so the transcript is observable in the dashboard and feeds the per-conversation history. |
GET /v1/agent/sessions/:page_id/messages |
List the recorded turns for a given page's recent conversation. Used by the public page's voice transcript and dashboard observability. |
POST /v1/agent/sessions/:page_id/finalize |
Mark a voice session as ended. Called when the visitor disconnects from the LiveKit room. |
POST /v1/agent/knowledge/search |
Search the page's knowledge graph for entities and facts. Backs the agent's search_knowledge function tool — lets the LLM pull facts mid-conversation without giving up client-side audio orchestration. |
Stripe subscription lifecycle. POST /v1/billing/subscribe is user-facing (Bearer JWT); POST /webhooks/stripe is Stripe-facing (signature-verified).
| Endpoint | Description |
|---|---|
POST /v1/billing/subscribe |
Start (or resume) a 7-day Stripe trial subscription for the authenticated user. Creates the Stripe customer if missing, creates the subscription with trial_period_days=7, flips the user's plan_tier to "trial". Returns 204 on success, 409 if already on an active subscription. |
POST /webhooks/stripe |
Stripe webhook receiver. Signature-verified via STRIPE_WEBHOOK_SECRET. Handles customer.subscription.created/updated/deleted and invoice.payment_succeeded/failed — updates the user's plan_tier based on subscription status, downgrades to "free" when the trial ends without conversion. NOTE: the route is /webhooks/stripe, not /v1/billing/webhook — configure the Stripe webhook endpoint URL accordingly. |
M2M secret required. Used by Auth0's Post-Login Action for user provisioning.
| Endpoint | Description |
|---|---|
POST /internal/users/provision |
Provision a user on first login. Body: {"auth0_sub": "...", "email": "...", "name": "...", "email_verified": true, "avatar_url": "..."}. Returns: {"user_id": "uuid", "role": "user"}. Idempotent: returns existing user if already provisioned. |
Optional JWT. Generates a LiveKit room token for voice sessions.
| Endpoint | Description |
|---|---|
POST /v1/pages/:page_id/room-token |
Generate a LiveKit JWT for joining a voice room. If a Bearer token is present and the caller owns the page, they join as the owner. Otherwise, they join as a visitor. The backend also dispatches the ambasdr-voice-agent to the room. |
The chat endpoints (/v1/public/pages/:slug/chat and /v1/agent/chat/stream) return Server-Sent Events with the following event types.
| Event | Payload and Meaning |
|---|---|
content |
Streamed text chunk from the LLM. data: {"text": "..."}. Append to the current assistant message. |
thread |
Thread ID for conversation continuity. data: {"thread_id": "uuid"}. Store and include in the next request to maintain context. |
done |
Stream completed. data: {}. The full assistant message has been delivered. |
error |
Stream error. data: {"error": "message"}. The stream will close after this event. |
The frontend's useAgentChat hook handles this protocol: it opens a fetch request, reads the SSE stream, appends content chunks to the active message, captures the thread ID for subsequent requests, and marks streaming as complete on the done event.
All non-streaming endpoints return errors in a standard format: {"error": {"code": "string", "message": "string", "request_id": "uuid"}}. HTTP status codes map to gommon's commonerrors: 400 (validation), 401 (unauthorized), 403 (forbidden), 404 (not found), 409 (conflict), 500 (internal).