API Reference
Complete reference for interacting with the Chat API
Endpoint
POST https://uncensored.chat/api/v1/chat/completionsHeaders
AuthorizationBearer YOUR_API_KEYContent-Typeapplication/jsonRequest Parameters
modelrequiredstringThe model to use for completion. E.g., "uncensored-v2"
messagesrequiredarrayArray of message objects. Each message has a "role" (user/assistant/system) and "content".
streamoptionalbooleanWhether to stream partial progress. Default: false
temperatureoptionalnumberSampling temperature between 0 and 2. Higher values make output more random.
max_tokensoptionalintegerMaximum number of tokens to generate in the completion.
Request Example
{
"model": "uncensored-v2",
"messages": [
{
"role": "user",
"content": "tell me a big story"
}
],
"stream": true,
"temperature": 0.7,
"max_tokens": 1000
}Response Examples
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1728345600,
"model": "uncensored-v2",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Here's a big story for you..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 150,
"total_tokens": 160
}
}Code Examples
curl -X POST https://uncensored.chat/api/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "uncensored-v2",
"messages": [
{
"role": "user",
"content": "tell me a big story"
}
],
"stream": true
}'Endpoint
GET https://uncensored.chat/api/v1/voice/charactersHeaders
AuthorizationBearer YOUR_API_KEYResponse Example
{
"object": "list",
"data": [
{
"id": 1,
"slug": "elon-musk",
"name": "Elon Musk",
"title": "CEO of Tesla & SpaceX",
"thumbnail": "https://...",
"first_message": "Hello there.",
"voice_sample_url": "https://...",
"voice_synced_at": "2024-01-01T00:00:00Z"
}
]
}Endpoint
POST https://uncensored.chat/api/v1/voice/callsHeaders
AuthorizationBearer YOUR_API_KEYContent-Typeapplication/jsonRequest Parameters
character_slugrequiredstringThe slug of the voice-ready character to talk with. Get available slugs from the List Voice Characters endpoint.
Request Example
{
"character_slug": "elon-musk"
}Response Example
{
"object": "voice.call",
"chat_id": "550e8400-e29b-41d4-a716-446655440000",
"ws_url": "wss://uncensored.chat/voice-ws?chat_id=...&exp=...&sig=...",
"mode": "live",
"minutes_remaining": 30,
"character": {
"slug": "elon-musk",
"name": "Elon Musk",
"thumbnail": "https://...",
"first_message": "Hello there.",
"voice_sample_url": "https://..."
}
}Code Examples
curl -X POST https://uncensored.chat/api/v1/voice/calls \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"character_slug": "elon-musk"
}'Connection Flow
- Call
POST /api/v1/voice/callsto get a signedws_url - Open a WebSocket connection to the
ws_url - Stream PCM audio to the server and receive PCM audio back
- Close the WebSocket when finished — usage is tracked automatically
Connection URL
wss://uncensored.chat/voice-ws?chat_id=UUID&exp=TIMESTAMP&sig=HMACThe ws_url from the start call response is pre-signed and expires after 10 minutes.
Protobuf Framing
All WebSocket messages use protobuf varint-length-prefixed framing. Each frame is a binary message with the following top-level structure:
| Field | Number | Type | Description |
|---|---|---|---|
| text | 1 | bytes | Text frame (bot text output) |
| audio | 2 | bytes | Audio frame (PCM data) |
| transcription | 3 | bytes | Transcription frame (user speech) |
| transport | 4 | bytes | Transport message (JSON events) |
Audio Input (Client → Server)
Send microphone audio as binary protobuf frames. Each audio message contains:
| Field | Number | Type | Value |
|---|---|---|---|
| audio_data | 3 | bytes | Raw PCM Int16 samples |
| sample_rate | 4 | int32 | 16000 Hz |
| num_channels | 5 | int32 | 1 (mono) |
Recommended chunk size: 50ms frames (800 samples at 16kHz).
Audio Output (Server → Client)
Receive TTS audio as binary protobuf frames with the same structure, but at 24kHz:
| Field | Number | Type | Value |
|---|---|---|---|
| audio_data | 3 | bytes | Raw PCM Int16 samples |
| sample_rate | 4 | int32 | 24000 Hz |
| num_channels | 5 | int32 | 1 (mono) |
Transport Messages
Server sends JSON transport messages (field 4) with label: "rtvi-ai" and event data:
user-started-speakingThe user began speaking. Interrupt any playing bot audio.
user-stopped-speakingThe user finished speaking. The bot will start processing.
user-transcriptionFinal transcription of user speech. data.text contains the transcribed text.
bot-llm-startedThe bot started generating a response.
bot-llm-textToken-level streaming text. data.text contains the delta.
bot-llm-stoppedThe bot finished generating text. TTS synthesis begins.
bot-started-speakingThe bot started speaking (audio frames incoming).
bot-stopped-speakingThe bot finished speaking. Commit the transcript.
bot-outputSentence-level aggregation of what the bot will speak. data.text contains the sentence.
errorAn error occurred. data.error contains the message.
WebSocket Example (JavaScript)
// 1. Start the call via REST API
const response = await fetch('https://uncensored.chat/api/v1/voice/calls', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ character_slug: 'elon-musk' })
});
const { ws_url } = await response.json();
// 2. Connect to the WebSocket
const ws = new WebSocket(ws_url);
ws.binaryType = 'arraybuffer';
ws.addEventListener('open', () => {
console.log('Voice call connected');
// Start sending microphone audio...
});
ws.addEventListener('message', (event) => {
if (event.data instanceof ArrayBuffer) {
// Decode protobuf frame (audio or transport message)
// See voice-call-client.ts for full decoder
}
});
ws.addEventListener('close', () => {
console.log('Voice call ended');
});