Skip to main content
By default, agents created on XUNA AI require authentication to start a conversation. This prevents unauthorized callers from consuming your quota or accessing your agent’s capabilities. Authentication is enforced at the connection layer — clients must present a valid signed URL or conversation token to open a session.
Never expose your XUNA AI API key in client-side code. All authentication artifacts (signed URLs and conversation tokens) must be generated on your server and passed to the client.

Signed URLs

A signed URL is a time-limited URL generated server-side that the client uses to open a WebSocket connection. It embeds your agent ID and authentication credentials so the client never needs your API key. Use signed URLs when you are connecting via the WebSocket API or need fine-grained control over the connection parameters.

Generate a signed URL

from xuna_ai import XunaAI

client = XunaAI()

response = client.conversational_ai.conversations.get_signed_url(
    agent_id="your-agent-id"
)

signed_url = response.signed_url
# Pass this URL to your client

Use the signed URL on the client

Pass the signed URL to the XUNA AI client SDK instead of the agent ID:
browser.js
import { Conversation } from "@xuna-ai/client";

// Fetch the signed URL from your server
const { signed_url } = await fetch("/get-signed-url").then(r => r.json());

const conversation = await Conversation.startSession({
  signedUrl: signed_url,
});

Conversation tokens

A conversation token is a short-lived token generated server-side that the client uses to initiate a WebRTC session. Conversation tokens also support dynamic variables and session overrides at creation time. Use conversation tokens when you are using the React SDK, mobile SDKs, or any WebRTC-based deployment, or when you want to attach per-session personalization data.

Generate a conversation token

from xuna_ai import XunaAI

client = XunaAI()

token_response = client.conversational_ai.conversations.get_token(
    agent_id="your-agent-id",
    # Optionally attach dynamic variables
    dynamic_variables={
        "user_name": "Jordan",
        "plan_name": "Pro",
    }
)

conversation_token = token_response.token
# Pass this token to your client

Use the conversation token on the client

Pass the token to the React SDK or client SDK:
import { useConversationControls } from "@xuna-ai/react";

function VoiceAgent() {
  const { startSession } = useConversationControls();

  const handleStart = async () => {
    // Fetch the token from your server
    const { token } = await fetch("/conversation-token").then(r => r.json());

    await startSession({ conversationToken: token });
  };

  return <button onClick={handleStart}>Start</button>;
}

Choosing between signed URLs and conversation tokens

Signed URLConversation token
TransportWebSocketWebRTC
SDK supportWebSocket API, @xuna-ai/clientReact SDK, iOS SDK, Android SDK, @xuna-ai/client
Session overridesAt connection timeAt token creation time
Dynamic variablesAt connection timeAt token creation time
Typical useCustom WebSocket clients, low-level integrationsAll SDK-based deployments

Public agents

If you want anyone to start a conversation without server-side authentication — for example, a public demo — you can mark the agent as public in the dashboard. Public agents accept connections without a signed URL or token.
Public agents consume your XUNA AI quota for every conversation started. Set a max conversation duration and monitor usage closely to avoid unexpected charges.

Custom authentication middleware

For advanced use cases — such as integrating with your own identity provider or enforcing business-specific access rules — you can implement custom authentication middleware on your server. The pattern is the same for both signed URLs and conversation tokens: your server authenticates the user through whatever mechanism you choose, then issues the XUNA AI credential only if authentication passes. See the server-side examples above for how to integrate user authentication with token generation.