Skip to Content

Why mint from your backend

Calling the session endpoint from your server (not the browser) lets you:

  • Keep your Oshara credentials server-side
  • Pass your logged-in user’s user_id, name, email, plan, etc. to the agent via metadata
  • Enforce your own session limits and logging
  • Reuse the same flow for native apps that don’t load the widget
Browser → POST /your-api/voice-token → Your backend → POST /api/agents/agent-session/ → Oshara Browser ← { token, livekit_url } ◄──────────────────────────────────────────────────────┘

Endpoint

POST /api/agents/agent-session/
FieldRequiredDescription
agentCharacter slug (e.g. support-bot)
languageBCP-47 code — overrides character default for STT/TTS
system_promptPer-session prompt override
greetingPer-session greeting override
voice_modelNamed voice (e.g. chatterbox-en-v1)
mcp_headersHeaders merged into every MCP server call this session
metadataArbitrary user/session context (user_id, email, plan, …)

Full endpoint reference: API Reference → Sessions.

Server-side example (Node.js)

// POST /your-api/voice-token app.post("/your-api/voice-token", requireAuth, async (req, res) => { const user = req.user; const session = await fetch("https://api.oshara.ai/api/agents/agent-session/", { method: "POST", headers: { "Content-Type": "application/json", "Origin": "https://yoursite.com" }, body: JSON.stringify({ agent: "support-bot", language: req.body.language || "en", metadata: { user_id: user.id, user_name: user.fullName, user_email: user.email, account_tier: user.plan, org_id: user.orgId } }) }).then(r => r.json()); res.json({ token: session.token, livekit_url: session.livekit_url, session_id: session.session_id }); });

Server-side example (Python)

import httpx from fastapi import APIRouter, Depends router = APIRouter() @router.post("/voice-token") async def get_voice_token(user=Depends(get_current_user)): async with httpx.AsyncClient() as client: r = await client.post( "https://api.oshara.ai/api/agents/agent-session/", headers={"Origin": "https://yoursite.com"}, json={ "agent": "support-bot", "metadata": { "user_id": str(user.id), "user_name": user.full_name, "user_email": user.email, } } ) data = r.json() return {"token": data["token"], "livekit_url": data["livekit_url"]}

Connect the browser with the LiveKit SDK

import { Room } from "livekit-client"; const { token, livekit_url } = await fetch("/your-api/voice-token", { method: "POST" }) .then(r => r.json()); const room = new Room(); await room.connect(livekit_url, token); // Mic, audio in/out, data channel are now active

Response shape

{ "token": "eyJhbGci...", "livekit_url": "wss://audio-inference.oshara.ai", "room_name": "oshara-voice-support-bot-user123-abc12", "participant_identity": "user-123-abc12", "session_id": "sess_a1b2c3", "expires_in_seconds": 3600, "character_slug": "support-bot", "system_prompt": "You are a helpful support agent...", "greeting": "Hi! How can I help you today?" }

Use session_id to filter form responses and logs after the call.

Errors

StatusCauseFix
403 ForbiddenOrigin header not on the character’s allowed_origins listAdd your domain via dashboard or PATCH /api/ai-characters/{slug}/
404 Not FoundWrong agent slugCheck spelling in the dashboard
429 Too Many RequestsConcurrent session limit reachedWait or upgrade plan
Last updated on