🎙️ Realtime API
Trò chuyện bằng giọng nói, hai chiều, độ trễ thấp — người dùng nói, model nghe và đáp lại bằng giọng ngay trong lúc nói, ngắt lời được như hội thoại thật.
Đây không phải /v1/chat/completions. Chat là hỏi một câu rồi chờ trả lời; realtime là một kết nối mở suốt cuộc nói chuyện, âm thanh chảy liên tục cả hai chiều.
Khác gì so với API thường
| Chat Completions | Realtime API | |
|---|---|---|
| Kết nối | một request, một response | mở suốt phiên (WebRTC hoặc WebSocket) |
| Dữ liệu | văn bản | âm thanh 2 chiều (kèm phụ đề nếu bật) |
| Ngắt lời | không | có |
| Tính tiền | theo token | theo token, từng loại (tiếng vào/ra, chữ vào/ra, ảnh, video, cache), chốt sổ mỗi 60 giây |
| Cách gọi | 1 bước | 2 bước: tạo phiên rồi nối kênh tiếng |
Model và giá
Model trò chuyện thời gian thực
| Model | Model ID | Hãng | Cách tính tiền | Giá |
|---|---|---|---|---|
| Gemini 3.8 Live | gemini-3.8-live | theo token | audio vào 137.500đ ($5.00)/1M token · audio ra 550.000đ ($20.00)/1M token · ≈ hội thoại thông thường 2.709đ ($0.099)/phút | |
| GPT Realtime 2.1 | gpt-realtime-2.1 | OpenAI | theo token | audio vào 1.375.000đ ($50.00)/1M token · audio ra 2.722.500đ ($99.00)/1M token · ≈ hội thoại thông thường 2.723đ ($0.099)/phút |
| GPT Realtime 2.1 Mini | gpt-realtime-2.1-mini | OpenAI | theo token | audio vào 426.250đ ($15.50)/1M token · audio ra 825.000đ ($30.00)/1M token · ≈ hội thoại thông thường 909đ ($0.033)/phút |
\uD83D\uDD04 Bảng trên lấy trực tiếp từ hệ thống, tự cập nhật khi danh mục model thay đổi. Giá tính bằng VND; số trong ngoặc là quy đổi tham khảo theo tỷ giá 1 USD = 27.500đ. Xem đầy đủ kèm rate limit tại trang Models.
Cả ba model tính theo token, trừ dần theo lượng âm thanh và chữ thực tế, chốt sổ mỗi 60 giây. Hai điều cần biết để ước tính chi phí:
- Ngữ cảnh được tính lại ở mỗi lượt nói. Với GPT Realtime, phần lặp lại tính theo giá cache (rẻ hơn nhiều lần). Gemini Live không có giá cache, nên hệ thống tự nén ngữ cảnh còn khoảng 8–12k token (≈ 5–8 phút audio gần nhất): model vẫn nhớ đoạn gần, hội thoại rất dài thì đoạn đầu bị lược bớt.
- Vì thế cột ≈ hội thoại thông thường ở bảng trên là ước tính cho một cuộc nói chuyện 2 lượt/phút, hai bên nói ngang nhau — cuộc gọi dài nhiều lượt với Gemini đắt hơn GPT Realtime Mini. Số tiền thật xem ở sự kiện
usage.settledhoặcGET /sessions/{id}sau khi kết thúc.
Bước 1 — Tạo phiên
POST https://platform.beeknoee.com/v1/realtime/sessions
| Header | Giá trị | Bắt buộc |
|---|---|---|
Authorization | Bearer YOUR_API_KEY | ✅ |
Content-Type | application/json | ✅ |
Tham số
| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
model | string | — | ✅ Model ID, ví dụ gemini-3.8-live |
transport | string | auto | auto | websocket | webrtc |
modalities | string[] | ["audio"] | Đầu ra: audio, text hoặc cả hai |
voice | string | theo model | Tên giọng của model (xem danh mục model) |
instructions | string | — | System prompt cho phiên |
tools | array | — | Function tool dạng JSON Schema |
turn_detection | object | null | theo model | null = tắt nhận diện lượt nói, client tự báo |
input_audio_transcription | boolean | true | Phụ đề lời người dùng |
output_audio_transcription | boolean | true | Phụ đề lời model |
input | object | {audio:true, video:false, text:true} | Cổng đầu vào. Bật video thì phiên bị kẹp 2 phút |
max_duration_sec | number | 1800 | Trần thời lượng của phiên: tối đa 3.600 với GPT Realtime, 86.400 (24 giờ) với Gemini Live |
max_spend_vnd | number | theo model | Trần chi cho phiên. Bỏ trống = tự tính theo giá model và thời lượng (tối thiểu 50.000đ); 0 = không trần |
metadata | object | — | Của bạn, tối đa 1 KB, trả lại nguyên |
Phản hồi
{
"id": "bee_rt_8Kq2mZ1vN4xPwTcR7hJdLs0y",
"object": "realtime.session",
"status": "created",
"model": "gpt-realtime-2.1-mini",
"engine_protocol": "openai-realtime-v1",
"transport": "webrtc",
"billing_basis": "token",
"connect_by": "2026-09-18T10:31:00.000Z",
"connection": {
"type": "webrtc",
"sdp_url": "https://platform.beeknoee.com/v1/realtime/sessions/bee_rt_8Kq2mZ1vN4xPwTcR7hJdLs0y/sdp",
"data_channel": "oai-events",
"token": "bee_rts_9f3c...",
"token_expires_at": "2026-09-18T10:31:00.000Z"
},
"billing": {
"currency": "VND",
"settle_interval_sec": 60,
"estimated_vnd_per_min": 1030,
"max_spend_vnd": 50000
}
}
token là token phiên, sống 60 giây và dùng đúng một lần. Nó thay cho API key ở bước 2, nên đưa xuống trình duyệt được mà không lộ key thật.
Phiên phải được nối trước mốc connect_by, quá hạn thì bị huỷ và không tính tiền.
Bước 2 — Nối kênh tiếng
Cả hai kiểu đều nối vào hệ thống realtime của Beeknoee. Trường connection.type cho biết phiên này dùng kiểu nào: WebRTC (mặc định với GPT Realtime) hoặc WebSocket (mặc định với Gemini Live; GPT Realtime cũng dùng được khi bạn chọn transport: "websocket"). connection.protocol cho biết khuôn sự kiện của model.
WebRTC — khuyên dùng cho trình duyệt
Bạn gửi SDP offer tới connection.sdp_url, Beeknoee trả SDP answer, rồi âm thanh chạy trực tiếp trên kênh WebRTC của phiên — độ trễ thấp nhất, trình duyệt tự lo micro và loa.
const pc = new RTCPeerConnection()
// Loa: gắn luồng âm thanh của model vào thẻ <audio>
pc.ontrack = (e) => { document.querySelector('audio').srcObject = e.streams[0] }
// Micro
const mic = await navigator.mediaDevices.getUserMedia({ audio: true })
pc.addTrack(mic.getTracks()[0])
// Kênh sự kiện của model (tên kênh nằm ở connection.data_channel)
const events = pc.createDataChannel(session.connection.data_channel)
events.onmessage = (e) => console.log(JSON.parse(e.data))
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)
const answer = await fetch(session.connection.sdp_url, {
method: 'POST',
headers: {
'Authorization': `Bearer ${session.connection.token}`,
'Content-Type': 'application/sdp',
},
body: offer.sdp,
}).then((r) => r.text())
await pc.setRemoteDescription({ type: 'answer', sdp: answer })
Cửa sdp nhận tối đa 5 lượt mỗi phút cho một phiên. Gọi lần thứ hai khi phiên đã nối sẽ nhận 409.
WebSocket
Đường mặc định của Gemini Live, và là lựa chọn cho máy chủ hoặc môi trường không dùng được WebRTC. Bạn mở một WebSocket tới connection.url, gửi âm thanh PCM16 16 kHz và nhận âm thanh PCM16 24 kHz cùng phụ đề, sự kiện của model và sự kiện tiền của Beeknoee — tất cả trên cùng một kết nối.
Với Gemini Live, phiên đã được cấu hình xong ở Bước 1 (model, giọng, prompt, nén ngữ cảnh) — bạn không gửi setup; gửi cũng bị bỏ. Chỉ gửi realtimeInput / clientContent / toolResponse.
const ws = new WebSocket(session.connection.url)
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
if (msg.bee) return console.log('Beeknoee:', msg.bee) // sự kiện của Beeknoee (tiền, phiên)
console.log('model:', msg) // sự kiện của model (khuôn theo connection.protocol)
}
// Gửi âm thanh: PCM16 16 kHz, mã hoá base64 — khuôn message theo connection.protocol
if (session.connection.protocol === 'gemini-live-v1beta') {
ws.send(JSON.stringify({ realtimeInput: { audio: { mimeType: 'audio/pcm;rate=16000', data: base64Pcm } } }))
} else {
ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: base64Pcm }))
}
Mỗi phiên chỉ cho một kết nối tại một thời điểm. Rớt mạng thì gọi POST /v1/realtime/sessions/:id/reconnect để lấy token mới, còn hạn nối lại là 120 giây.
Phiên dài (Gemini Live)
Gemini Live chạy được một phiên liên tục tới 24 giờ: khai max_duration_sec tới 86400 khi tạo phiên. Kết nối bên dưới được Beeknoee tự làm mới định kỳ trong lúc phiên chạy — ứng dụng không phải làm gì và không nhận thấy gì, ngữ cảnh hội thoại được giữ nguyên (phần rất cũ tự lược bớt như đã nói ở mục Model). Hai việc nên làm ở phía ứng dụng:
- Giữ luồng tiếng chảy liên tục. Phiên không có tiếng và không có sự kiện nào trong 3 phút sẽ tự kết thúc.
- Xử lý
session.terminatednhư một việc bình thường (Beeknoee bảo trì, hoặc hết thời lượng đã khai): tạo phiên mới rồi nối lại; ngữ cảnh của phiên cũ không mang sang.
GPT Realtime dừng ở 60 phút mỗi phiên; ứng dụng chạy dài trên model này tạo phiên mới sau mỗi giờ.
Mã đóng của Beeknoee:
| Mã | Nghĩa |
|---|---|
4000 | Phiên đã kết thúc bình thường |
4400 | Sai định dạng: chỉ nhận JSON dạng text, không nhận khung nhị phân |
4409 | Token đã dùng, hoặc phiên đang có kết nối khác |
4413 | Gửi nhanh hơn mức hệ thống nhận được |
4503 | Không mở được kênh tiếng — tạo phiên mới và thử lại |
Sự kiện của Beeknoee
Trên kênh WebSocket, sự kiện của Beeknoee nằm dưới khoá bee để không lẫn với sự kiện của model:
bee.type | Khi nào |
|---|---|
session.active | Đã nối xong, phiên bắt đầu tính tiền |
usage.settled | Vừa chốt một cửa sổ 60 giây, kèm số tiền |
warning.low_balance | Ví sắp không đủ cho cửa sổ kế |
warning.max_spend | Đã dùng quá 80% trần chi của phiên |
session.ended | Kết thúc bình thường |
session.terminated | Bị cắt: hết tiền, quá trần, API key bị tạm ngừng / thu hồi / hết hạn hoặc chạm hạn mức chi tiêu, hoặc lỗi hệ thống |
Với WebRTC, kênh dữ liệu chỉ chở sự kiện của model; sự kiện tiền và phiên của Beeknoee đi qua kênh riêng:
GET https://platform.beeknoee.com/v1/realtime/sessions/{id}/events
Đây là SSE, tự đóng sau khi phiên kết thúc.
Kết thúc và tra cứu
# Kết thúc phiên (chốt sổ rồi đóng kênh tiếng)
curl -X DELETE https://platform.beeknoee.com/v1/realtime/sessions/{id} \
-H "Authorization: Bearer $BEEKNOEE_API_KEY"
# Xem một phiên
curl https://platform.beeknoee.com/v1/realtime/sessions/{id} \
-H "Authorization: Bearer $BEEKNOEE_API_KEY"
# Lịch sử phiên
curl https://platform.beeknoee.com/v1/realtime/sessions?limit=20 \
-H "Authorization: Bearer $BEEKNOEE_API_KEY"
# Danh mục model realtime kèm giá theo gói của bạn
curl https://platform.beeknoee.com/v1/realtime/models \
-H "Authorization: Bearer $BEEKNOEE_API_KEY"
Phiên đã kết thúc trả về đầy đủ usage và billing, đối chiếu được với lịch sử ví.
Ví dụ
Mẫu chung của mọi ví dụ: máy chủ của bạn giữ API key và tạo phiên; trình duyệt chỉ nhận connection (token phiên sống 60 giây, dùng một lần) rồi tự nối kênh tiếng như ở Bước 2.
1. Tạo phiên — cURL
curl -X POST https://platform.beeknoee.com/v1/realtime/sessions \
-H "Authorization: Bearer sk-bee-your-key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-realtime-2.1-mini",
"instructions": "You are a concise customer-support assistant. Answer in the caller'"'"'s language.",
"max_spend_vnd": 20000
}'
2. Python — máy chủ tạo phiên, đưa connection xuống trình duyệt
import requests
BEE = "https://platform.beeknoee.com/v1"
HEADERS = {"Authorization": "Bearer sk-bee-your-key"}
# Máy chủ giữ API key; trình duyệt chỉ nhận `connection` (token phiên 60 giây, dùng một lần)
session = requests.post(f"{BEE}/realtime/sessions", headers=HEADERS, json={
"model": "gpt-realtime-2.1-mini",
"instructions": "You are a concise customer-support assistant. Answer in the caller's language.",
"max_spend_vnd": 20000,
}).json()
print(session["id"], session["connection"]["type"])
# → gửi session["connection"] cho trình duyệt (xem Bước 2). KHÔNG gửi API key.
3. Node.js — máy chủ tạo phiên
// Máy chủ (Node 18+): tạo phiên, chỉ trả `id` + `connection` cho trình duyệt
const res = await fetch('https://platform.beeknoee.com/v1/realtime/sessions', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk-bee-your-key', 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'gpt-realtime-2.1-mini', max_duration_sec: 600 }),
})
const session = await res.json()
// trả cho trình duyệt: { id: session.id, connection: session.connection }
Trình duyệt nhận connection rồi chạy đúng đoạn WebRTC ở Bước 2 bên trên.
4. Gemini Live — tạo phiên rồi nối WebSocket — Node.js / trình duyệt
// Máy chủ tạo phiên Gemini — nhận connection.type = "websocket", protocol = "gemini-live-v1beta"
const res = await fetch('https://platform.beeknoee.com/v1/realtime/sessions', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk-bee-your-key', 'Content-Type': 'application/json' },
body: JSON.stringify({ model: 'gemini-3.8-live', instructions: 'You are a friendly language tutor.' }),
})
const session = await res.json()
// Trình duyệt mở WebSocket; KHÔNG gửi setup — phiên đã được cấu hình xong ở Bước 1
const ws = new WebSocket(session.connection.url)
ws.onmessage = (e) => {
const msg = JSON.parse(e.data)
if (msg.bee) return console.log('Beeknoee:', msg.bee)
const part = msg.serverContent?.modelTurn?.parts?.[0]
if (part?.inlineData) playPcm24k(part.inlineData.data) // tiếng của model: PCM16 24 kHz, base64
}
ws.onopen = () => ws.send(JSON.stringify({ realtimeInput: { audio: { mimeType: 'audio/pcm;rate=16000', data: base64Pcm } } }))
5. Theo dõi tiền trong lúc nói — SSE
# Dòng sự kiện của Beeknoee cho một phiên (usage.settled, warning.low_balance, session.ended…)
curl -N https://platform.beeknoee.com/v1/realtime/sessions/bee_rt_xxx/events \
-H "Authorization: Bearer sk-bee-your-key"
Giới hạn
| Giới hạn | Giá trị |
|---|---|
| Phiên đồng thời | 3 (Free) · 10 (Basic) · 20 (Advanced) · 50 (Ultra) — cần nhiều hơn thì liên hệ hỗ trợ |
| Tạo phiên | 60 lượt POST /sessions mỗi phút cho một tài khoản, tính chung mọi API key; quá thì 429 |
| Thời lượng một phiên | mặc định 30 phút · tối đa 60 phút với GPT Realtime, 24 giờ với Gemini Live |
| Có bật video | tối đa 2 phút |
| Không hoạt động | 3 phút không có tiếng và không có sự kiện ⇒ phiên tự kết thúc (idle) |
| Token phiên | 60 giây, dùng một lần |
| Nối lại sau khi rớt | trong 120 giây |
Ứng dụng chạy liên tục: xem mục "Phiên dài (Gemini Live)" ở Bước 2.
Lỗi thường gặp
| Mã | Ý nghĩa | Làm gì |
|---|---|---|
realtime_model_not_configured | Model chưa có đủ bảng giá | Chọn model khác, hoặc báo hỗ trợ |
realtime_no_route | Model tạm thời không khả dụng | Thử lại sau ít phút, hoặc chọn model khác |
rate_limit_exceeded (HTTP 429) | Tạo quá 60 phiên trong một phút | Chờ 60 giây rồi tạo lại |
realtime_session_limit | Vượt số phiên đồng thời của gói | Kết thúc phiên cũ trước |
insufficient_balance | Ví không đủ để mở phiên | Nạp thêm tiền |
realtime_token_expired | Token phiên quá 60 giây | Tạo phiên mới |
realtime_session_already_connected | Phiên đang có kết nối khác | Dùng /reconnect thay vì nối mới |
realtime_video_not_allowed | Model không nhận video | Tắt input.video |
Chi tiết khuôn lỗi xem bài Xử lý lỗi.