نِت اَرز · مستندات API هوش مصنوعی
همهٔ مستندات
مدل‌ها و قیمت‌ها مرجع تعاملی دریافت کلید

اتصال زنده (Realtime)

گفت‌وگوی صوتی زنده روی WebSocket، سازگار با OpenAI Realtime API: پاسخ‌گوی تلفنی، دستیار صوتی و اتصال به Asterisk با A-law و μ-law، تشخیص پایان گفتار، فراخوانی ابزار و نمونه‌کد Node.js و Python.

base_url: https://netarz.ir/api/ai/v1 به‌روزرسانی: 1405/07/25

با اتصال زنده (Realtime) یک گفت‌وگوی صوتی دوطرفه روی یک اتصال WebSocket دارید: صدای کاربر را همان لحظه که حرف می‌زند می‌فرستید و پاسخ مدل را تکه‌تکه، هم به‌صورت صدا و هم متن، پس می‌گیرید. بیشتر برای تلفن گویا و دستیار صوتی به کار می‌رود: منشی تلفنی، ثبت سفارش تلفنی یا پاسخ‌گوی مرکز تماس. پروتکل با OpenAI Realtime API (نام رویدادهای نسخهٔ نهایی یا GA) سازگار است، پس کد و کتابخانه‌ای که برای آن نوشته شده با عوض کردن نشانی و کلید کار می‌کند.

WSS wss://netarz.ir/api/ai/v1/realtime?model=<model-id> نیازمند کلید API
WSS wss://ir.gisoo.pro/api/v1/realtime?model=<model-id> نیازمند کلید API
سرور داخل ایران

اگر سرور شما در دیتاسنتری داخل ایران است، به نشانی wss://ir.gisoo.pro/api/v1/realtime وصل شوید؛ از این دیتاسنترها درخواست به netarz.ir درست نمی‌رسد. کلید، اعتبار و گزارش مصرف در هر دو نشانی یکی است.

چطور کار می‌کند

  1. اتصال سرور شما با هدر Authorization: Bearer <کلید> به نشانی بالا وصل می‌شود و مدل را در پارامتر model می‌گوید. پیام session.created یعنی جلسه باز است.
  2. تنظیم جلسه با session.update دستور سیستمی (instructions)، قالب صدا، صدای گوینده و ابزارها را تعیین می‌کنید.
  3. فرستادن صدا صدای تماس‌گیرنده را تکه‌تکه با input_audio_buffer.append می‌فرستید. به‌طور پیش‌فرض سرویس خودش پایان حرف را تشخیص می‌دهد (server_vad) و پاسخ را شروع می‌کند.
  4. گرفتن پاسخ صدای پاسخ در response.output_audio.delta و متن همان پاسخ در response.output_audio_transcript.delta می‌رسد. اگر مدل ابزاری را صدا بزند، شما تابع خودتان را اجرا می‌کنید و نتیجه را برمی‌گردانید.

دو نوع مدل روی اتصال زنده کار می‌کند. مدل‌های گفتاری مستقیم (GPT Realtime و Gemini Live) صدا را خودشان می‌شنوند و خودشان با صدا جواب می‌دهند؛ مکث پیش از پاسخ در آن‌ها کوتاه‌تر است و برای پاسخ‌گوی تلفنی و فروش تلفنی مناسب‌ترند. در بقیهٔ مدل‌ها خروجی مدل متن است. وقتی خروجی صوتی روشن است، سرویس همان متن را تکه‌به‌تکه به گفتار تبدیل می‌کند و اول عبارت کوتاهی می‌فرستد تا تماس‌گیرنده شروع پاسخ را بشنود و بقیه‌اش در همان حال نوشته شود. در این حالت یک دستور کوتاه هم به دستور سیستمی شما اضافه می‌شود تا مدل با جمله‌های ساده و گفتاری جواب بدهد، بدون Markdown، فهرست یا ایموجی.

اتصال و احراز هویت

  • کلید را در هدر Authorization: Bearer … یا X-API-Key بفرستید؛ همان کلید پروژه‌ای که برای درخواست‌های HTTP دارید.
  • کلید پیش از باز شدن اتصال بررسی می‌شود، درست مثل یک درخواست HTTP: باطل یا منقضی یا غیرفعال بودن کلید، فهرست IPهای مجاز و فهرست مدل‌های مجاز کلید و پروژه.
  • اگر اتصال پذیرفته نشود، WebSocket باز نمی‌شود و یک پاسخ HTTP معمولی (۴۰۱، ۴۰۲، ۴۰۳، ۴۲۹ یا ۵۰۳) با همان قالب خطای {"error": {...}} می‌گیرید.
  • مدل را در نشانی انتخاب می‌کنید و تا پایان جلسه عوض نمی‌شود.
  • پارامتر اختیاری codec قالب صدای ورودی و خروجی را از همان لحظهٔ اتصال تعیین می‌کند: alaw و ulaw (G.711 با ۸ کیلوهرتز، همان چیزی که Asterisk می‌دهد)، pcm8، pcm16 و pcm24 (PCM شانزده‌بیتی با ۸، ۱۶ یا ۲۴ کیلوهرتز). مقدار ناشناخته خطای ۴۰۰ invalid_codec می‌دهد.
کلید را در صفحهٔ وب نگذارید

مرورگر نمی‌تواند هدر Authorization را روی WebSocket بگذارد و کلید هم نباید به دست کاربر برسد. این API برای ارتباط سرور با سرور است: مرورگر یا اپ شما به سرور خودتان وصل می‌شود و سرور شما به نِت اَرز.

اتصال ردشده
HTTP/1.1 402 Payment Required
Content-Type: application/json; charset=utf-8

{"error": {"message": "…", "type": "insufficient_quota", "code": "insufficient_credit", "param": null}}

مدل‌ها

شناسهٔ مدلسازندهنوعمناسب برای
gpt-realtime-2.1OpenAIگفتاری مستقیمفروش و پشتیبانی تلفنی، وقتی کیفیت گفت‌وگو از هزینه مهم‌تر است
gpt-realtime-2.1-miniOpenAIگفتاری مستقیمبیشتر تماس‌ها؛ کم‌هزینه‌تر از نسخهٔ کامل
gemini-3.8-liveGoogleگفتاری مستقیمگفت‌وگوی طبیعی فارسی با هزینهٔ کمتر از GPT Realtime
qwen3.8-omni-flash-realtimeAlibaba (Qwen)گفتاری مستقیمپاسخ‌گوی تلفنی فارسی با مکث کوتاه و هزینهٔ کم
qwen/qwen3.8-omni-flashQwenمتن، سپس تبدیل به گفتارآزمایش و تماس‌های ساده
  • مدل‌های گفتاری مستقیم فقط روی همین اتصال کار می‌کنند؛ برای همین در فهرست GET /models نیستند و در /chat/completions پذیرفته نمی‌شوند.
  • صدای گوینده را در audio.output.voice بدهید: در GPT Realtime یکی از صداهای OpenAI (مثل marin، cedar یا alloy) و در Gemini Live یکی از صداهای Gemini (مثل Kore، Puck، Charon یا Aoede). در Gemini Live نام ناشناخته صدای Kore را می‌گیرد. در Qwen Realtime صدای پیش‌فرض Tina است و نام صداهای OpenAI همان صدای پیش‌فرض را می‌گیرد.
  • در qwen3.8-omni-flash-realtime تصویر فقط JPEG (به شکل data:image/jpeg;base64,…) پذیرفته می‌شود، tool_choice و تنظیمات جداگانه در response.create اثری ندارند، و conversation.item.truncate فقط تأیید می‌شود: پاسخ قطع‌شده در حافظهٔ گفت‌وگوی مدل کامل می‌ماند.
  • در Gemini Live دستور سیستمی، صدا و ابزارها را در همان اولین session.update بدهید. تغییرشان در میانهٔ جلسه هم پذیرفته می‌شود، ولی اتصال به مدل از نو برقرار می‌شود و ممکن است یک لحظه مکث بشنوید. پیام‌های conversation.item.create در Gemini Live فقط متن می‌پذیرند؛ صدا را با input_audio_buffer.append بفرستید.

از مدل‌های دیگر، هر مدل گفت‌وگوی فعالی که ورودی صوتی بپذیرد کار می‌کند. پیشنهاد ما qwen/qwen3.8-omni-flash است؛ شناسهٔ کاملش openrouter/qwen/qwen3.8-omni-flash است و نام کوتاه هم به همان مدل می‌رسد. مدلی که ورودی صوتی ندارد، پیش از باز شدن اتصال خطای model_not_realtime می‌گیرد. فهرست مدل‌ها را در مدل‌ها و قیمت‌ها ببینید.

نمونهٔ کامل: پاسخ‌گوی تلفنی با ثبت سفارش

این نمونه به gisoo.pro وصل می‌شود، صدای تماس را با قالب A-law می‌فرستد و می‌گیرد، متن پاسخ را ثبت می‌کند، وقتی تماس‌گیرنده وسط حرف دستیار شروع به صحبت کند پخش را قطع می‌کند، و سفارش را با ابزار place_order ثبت می‌کند. شیء call نمایندهٔ خط تلفن در برنامهٔ شماست.

Node.js (ws)
// npm install ws
import WebSocket from "ws";

// Outside Iranian data centres you may use wss://netarz.ir/api/ai/v1/realtime instead.
const URL = "wss://ir.gisoo.pro/api/v1/realtime?model=qwen/qwen3.8-omni-flash&codec=alaw";

const ws = new WebSocket(URL, {
  headers: { Authorization: `Bearer ${process.env.NETARZ_API_KEY}` },
});

// A refused connection (bad key, no credit, wrong model…) is a plain HTTP response.
ws.on("unexpected-response", (req, res) => {
  let body = "";
  res.on("data", (chunk) => (body += chunk));
  res.on("end", () => console.error("refused:", res.statusCode, body));
});

ws.on("open", () => {
  ws.send(JSON.stringify({
    type: "session.update",
    session: {
      instructions: "You answer the phone for a pizza shop. Speak Persian, short and polite.",
      audio: { output: { voice: "alloy" } },
      tools: [{
        type: "function",
        name: "place_order",
        description: "Register the caller's order once items and address are confirmed.",
        parameters: {
          type: "object",
          properties: {
            items: { type: "array", items: { type: "string" } },
            address: { type: "string" },
          },
          required: ["items", "address"],
        },
      }],
    },
  }));

  // `call` is your telephony leg (e.g. Asterisk AudioSocket): raw A-law 8 kHz frames.
  call.on("audio", (frame) => {
    ws.send(JSON.stringify({ type: "input_audio_buffer.append", audio: frame.toString("base64") }));
  });
});

ws.on("message", async (data) => {
  const event = JSON.parse(data);

  switch (event.type) {
    case "response.output_audio.delta":
      call.play(Buffer.from(event.delta, "base64")); // already A-law: no conversion
      break;

    case "input_audio_buffer.speech_started":
      call.stopPlayback(); // the caller is talking over the answer
      break;

    case "response.output_audio_transcript.done":
      console.log("assistant:", event.transcript);
      break;

    case "response.function_call_arguments.done": {
      const args = JSON.parse(event.arguments);
      const result = await placeOrder(args); // your own code
      ws.send(JSON.stringify({
        type: "conversation.item.create",
        item: { type: "function_call_output", call_id: event.call_id, output: JSON.stringify(result) },
      }));
      ws.send(JSON.stringify({ type: "response.create" }));
      break;
    }

    case "error":
      console.error(event.error.code, event.error.message);
      break;
  }
});

ws.on("close", (code, reason) => console.log("closed", code, reason.toString()));
Python (websockets)
# pip install websockets   (v14+; older versions name the argument extra_headers)
import asyncio, base64, json, os
import websockets

URL = "wss://ir.gisoo.pro/api/v1/realtime?model=qwen/qwen3.8-omni-flash&codec=alaw"

PLACE_ORDER = {
    "type": "function",
    "name": "place_order",
    "description": "Register the caller's order once items and address are confirmed.",
    "parameters": {
        "type": "object",
        "properties": {
            "items": {"type": "array", "items": {"type": "string"}},
            "address": {"type": "string"},
        },
        "required": ["items", "address"],
    },
}

async def run(call):
    headers = {"Authorization": f"Bearer {os.environ['NETARZ_API_KEY']}"}
    async with websockets.connect(URL, additional_headers=headers) as ws:
        await ws.send(json.dumps({"type": "session.update", "session": {
            "instructions": "You answer the phone for a pizza shop. Speak Persian, short and polite.",
            "tools": [PLACE_ORDER],
        }}))

        async def caller_audio():
            async for frame in call.frames():          # raw A-law 8 kHz bytes
                await ws.send(json.dumps({"type": "input_audio_buffer.append",
                                          "audio": base64.b64encode(frame).decode()}))

        sender = asyncio.create_task(caller_audio())
        try:
            async for message in ws:
                event = json.loads(message)
                kind = event["type"]

                if kind == "response.output_audio.delta":
                    call.play(base64.b64decode(event["delta"]))
                elif kind == "input_audio_buffer.speech_started":
                    call.stop_playback()
                elif kind == "response.output_audio_transcript.done":
                    print("assistant:", event["transcript"])
                elif kind == "response.function_call_arguments.done":
                    result = place_order(**json.loads(event["arguments"]))   # your own code
                    await ws.send(json.dumps({"type": "conversation.item.create", "item": {
                        "type": "function_call_output",
                        "call_id": event["call_id"],
                        "output": json.dumps(result),
                    }}))
                    await ws.send(json.dumps({"type": "response.create"}))
                elif kind == "error":
                    print("error:", event["error"]["code"], event["error"]["message"])
        finally:
            sender.cancel()

# A refused connection raises websockets.exceptions.InvalidStatus;
# e.response.status_code and e.response.body hold the usual {"error": {...}} JSON.

اتصال به Asterisk

AudioSocket و ExternalMedia در Asterisk صدای تماس را به شکل slin، alaw یا ulaw با ۸ کیلوهرتز می‌دهند. کافی است همان قالب را در نشانی بگویید: codec=alaw یا codec=ulaw، و برای slin مقدار codec=pcm8. آن‌وقت صدای تماس را بی‌تغییر می‌فرستید و صدای پاسخ را هم بی‌تغییر روی خط پخش می‌کنید؛ به تبدیل نرخ نمونه‌برداری یا قالب نیازی نیست. برنامهٔ میان Asterisk و این API (مثل نمونهٔ بالا) را خودتان می‌نویسید؛ ماژول آماده‌ای برای Asterisk نداریم.

تنظیم جلسه (session.update)

session.update با همهٔ گزینه‌ها
{
  "type": "session.update",
  "session": {
    "output_modalities": ["audio"],
    "instructions": "You are the receptionist of a dental clinic. Speak Persian.",
    "audio": {
      "input": {
        "format": { "type": "audio/pcm", "rate": 16000 },
        "turn_detection": {
          "type": "server_vad",
          "threshold": 0.5,
          "prefix_padding_ms": 300,
          "silence_duration_ms": 500,
          "create_response": true,
          "interrupt_response": true
        }
      },
      "output": {
        "format": { "type": "audio/pcm", "rate": 16000 },
        "voice": "coral",
        "model": "gpt-4o-mini-tts",
        "instructions": "Warm, calm and unhurried."
      }
    },
    "tools": [],
    "tool_choice": "auto",
    "temperature": 0.7,
    "max_output_tokens": 1024,
    "reasoning": { "effort": "none" }
  }
}
فیلدتوضیح
output_modalities["audio"] (پیش‌فرض: پاسخ گفتاری و متن آن) یا ["text"] (فقط متن).
instructionsدستور سیستمی، تا ۲۰٬۰۰۰ نویسه.
audio.input.format{"type":"audio/pcm","rate":8000|16000|24000} (شانزده‌بیتی little-endian، تک‌کاناله؛ پیش‌فرض ۲۴۰۰۰)، {"type":"audio/pcmu"} (G.711 μ-law، ۸ کیلوهرتز) یا {"type":"audio/pcma"} (G.711 A-law، ۸ کیلوهرتز). نام‌های نسخهٔ بتا (pcm16، g711_ulaw، g711_alaw) هم پذیرفته می‌شوند.
audio.output.formatهمان گزینه‌ها؛ اگر تعیین نکنید، خروجی همان قالب ورودی را دارد.
audio.input.turn_detectionتشخیص خودکار پایان گفتار (server_vad، پیش‌فرض) با threshold بین ۰ و ۱ (پیش‌فرض ۰٫۵)، prefix_padding_ms (۳۰۰)، silence_duration_ms (۵۰۰)، create_response و interrupt_response (هر دو true). با null خودتان commit و response.create می‌فرستید.
audio.output.voiceنام صدای گوینده؛ پیش‌فرض alloy. صداهای gpt-4o-mini-tts: alloy، ash، ballad، coral، echo، fable، nova، onyx، sage، shimmer، verse.
audio.output.modelمدل گفتار از فهرست مدل‌ها؛ پیش‌فرض gpt-4o-mini-tts. مدل‌های Gemini TTS هم کار می‌کنند و فارسی را طبیعی‌تر می‌خوانند، ولی هر جمله حدود ۳ ثانیه دیرتر می‌رسد.
audio.output.instructionsلحن و حال‌وهوای گوینده برای مدل گفتار، تا ۱۰۰۰ نویسه.
tools / tool_choiceابزارهای تابعی ({"type":"function","name","description","parameters"})، حداکثر ۶۴ ابزار و ۶۴ کیلوبایت. tool_choice: auto، none، required یا {"type":"function","name":"…"}.
temperatureبین ۰ و ۲.
max_output_tokensبین ۱ و ۱۶٬۳۸۴، یا "inf".
reasoningافزودهٔ نِت اَرز: {"effort":"none"|"low"|"medium"|"high"}. پیش‌فرض none است، چون فکر کردن مدل پیش از پاسخ چند ثانیه به شروع جواب اضافه می‌کند و تماس‌گیرنده آن را سکوت می‌شنود.

نوبت‌ها و قطع کردن حرف

با server_vad سرویس پایان حرف تماس‌گیرنده را تشخیص می‌دهد، صدا را commit می‌کند و پاسخ می‌سازد. اگر تماس‌گیرنده وسط ساخته شدن پاسخ شروع به حرف زدن کند، پاسخ لغو می‌شود (interrupt_response) و رویداد input_audio_buffer.speech_started می‌رسد. پخش صدایی را که پیش‌تر گرفته‌اید باید خودتان قطع کنید. اگر بخواهید مدل بداند تماس‌گیرنده تا کجای پاسخ را شنیده، conversation.item.truncate بفرستید:

نگه داشتن فقط بخش شنیده‌شده
{"type": "conversation.item.truncate", "item_id": "item_7Kx2…", "content_index": 0, "audio_end_ms": 1800}

اگر نوبت‌ها را خودتان مدیریت می‌کنید (مثلاً با دکمه‌ای که کاربر هنگام حرف زدن نگه می‌دارد، یا Push-to-talk)، تشخیص خودکار را خاموش کنید:

نوبت دستی
{"type": "session.update", "session": {"audio": {"input": {"turn_detection": null}}}}

{"type": "input_audio_buffer.append", "audio": "<base64 audio>"}
{"type": "input_audio_buffer.append", "audio": "<base64 audio>"}
{"type": "input_audio_buffer.commit"}
{"type": "response.create"}

برای پاسخ فقط متنی، یا فرستادن متن به‌جای صدا:

حالت متنی
{"type": "session.update", "session": {"output_modalities": ["text"]}}

{"type": "conversation.item.create", "item": {
  "type": "message", "role": "user",
  "content": [{"type": "input_text", "text": "ساعت کاری شما تا کی است؟"}]
}}
{"type": "response.create"}

فراخوانی ابزار (Function Calling)

ابزارها را در session.update تعریف می‌کنید. وقتی مدل ابزاری را صدا بزند، آرگومان‌هایش در response.function_call_arguments.done می‌رسد. تابع خودتان را اجرا کنید (مثلاً سفارش را ثبت کنید)، نتیجه را با conversation.item.create و {"type":"function_call_output","call_id":…,"output":"<رشتهٔ JSON>"} برگردانید و سپس response.create بفرستید تا مدل نتیجه را به تماس‌گیرنده بگوید.

رویدادها

رویدادهای کلاینت (شما می‌فرستید)

typeکار
session.updateتنظیم جلسه (بخش «تنظیم جلسه» در پایین). هر وقت لازم شد دوباره بفرستید.
input_audio_buffer.appendیک تکه صوت تماس‌گیرنده، base64 و با قالب ورودی جلسه.
input_audio_buffer.commitپایان نوبت تماس‌گیرنده؛ فقط وقتی تشخیص خودکار گفتار خاموش است لازم می‌شود.
input_audio_buffer.clearدور ریختن صوتی که هنوز commit نشده.
conversation.item.createافزودن پیام به گفت‌وگو: برای user با input_text یا input_audio، برای assistant و system با text؛ یا نتیجهٔ ابزار با type: function_call_output.
conversation.item.deleteحذف یک آیتم از گفت‌وگو.
conversation.item.retrieveگرفتن یک آیتم گفت‌وگو.
conversation.item.truncateوقتی تماس‌گیرنده وسط پاسخ حرف زد: فقط بخشی از پاسخ را که واقعاً شنیده (تا audio_end_ms) در گفت‌وگو نگه می‌دارد.
response.createگرفتن پاسخ از مدل.
response.cancelمتوقف کردن پاسخی که در حال ساخت است.

هر رویداد دیگری خطای unsupported_event می‌گیرد.

رویدادهای سرور (شما می‌گیرید)

typeمعنا
session.created / session.updatedجلسه باز شد / تنظیمات تازه پذیرفته شد (تنظیمات کامل جلسه همراهش می‌آید).
input_audio_buffer.speech_started / speech_stoppedتماس‌گیرنده شروع به حرف زدن کرد / ساکت شد. با speech_started پخش صدای خودتان را قطع کنید.
input_audio_buffer.committed / clearedنوبت تماس‌گیرنده ثبت شد / بافر خالی شد.
conversation.item.added / done / deleted / retrieved / truncatedتغییرات آیتم‌های گفت‌وگو.
response.createdساخت پاسخ شروع شد.
response.output_item.added / doneیک آیتم خروجی (پیام یا فراخوانی ابزار) شروع شد / تمام شد.
response.content_part.added / doneیک بخش از محتوای پیام شروع شد / تمام شد.
response.output_audio.delta / doneصدای پاسخ، base64 و با قالب خروجی جلسه، در قاب‌های حدوداً ۲۰۰ میلی‌ثانیه‌ای.
response.output_audio_transcript.delta / doneمتن همان پاسخ گفتاری، هم‌زمان با نوشته شدنش.
response.output_text.delta / doneپاسخ متنی، وقتی output_modalities برابر ["text"] است.
response.function_call_arguments.delta / doneآرگومان‌های فراخوانی ابزار؛ در done، مقدار call_id، name و arguments کامل می‌آید.
response.doneپایان پاسخ با status (completed، cancelled، incomplete یا failed) و مصرف توکن.
errorخطا؛ جلسه باز می‌ماند مگر خود خطا بگوید بسته شده است.

محدودیت‌ها

موردسقف
یک پیام WebSocket۱ مگابایت
سرعت فرستادن صداحداکثر چهار برابر زمان واقعی
یک نوبت گفتار۶۰ ثانیه
حافظهٔ گفت‌وگو۲۰۰ آیتم آخر؛ از صدای تماس‌گیرنده فقط حدود ۲ مگابایت آخر به‌صورت صدا به مدل می‌رسد. صدای نوبت‌های قدیمی‌تر دیگر به مدل نمی‌رسد، ولی متن‌ها و پاسخ‌ها می‌مانند.
طول جلسهیک ساعت، یا ۱۲۰ ثانیه بدون هیچ پیامی از سمت شما
جلسه‌های هم‌زمان۱۰ جلسه برای هر حساب
  • هر نوبت پاسخ مثل یک درخواست معمولی حساب می‌شود: یکی از درخواست‌های هم‌زمان حساب و یکی از سقف درخواست در دقیقهٔ کلید (RPM) را می‌گیرد (محدودیت‌ها و امنیت).
  • سرور هر ۲۵ ثانیه ping می‌فرستد. کتابخانه‌های WebSocket خودشان جواب pong را می‌دهند و کاری لازم نیست.
  • اگر کلید را باطل کنید، جلسه‌های باز آن کلید حداکثر حدود ۳۰ ثانیه بعد بسته می‌شوند.

سرعت پاسخ

در اندازه‌گیری‌های ما با qwen/qwen3.8-omni-flash، متن پاسخ معمولاً ۳ تا ۴ ثانیه بعد از ساکت شدن تماس‌گیرنده شروع می‌شود و اولین تکهٔ گفتاری با gpt-4o-mini-tts حدود یک ثانیه بعد از آن می‌رسد. این عددها تضمینی نیستند و به طول گفت‌وگو، مدل و شلوغی سرویس‌دهنده بستگی دارند. مدل‌های گفتاری مستقیم (جدول «مدل‌ها») چون صدا را خودشان می‌شنوند و می‌سازند، این مکث را ندارند و برای تماس تلفنی پیشنهاد ما همین‌ها هستند. برای کوتاه‌تر شدن مکث، reasoning.effort را روی none بگذارید و در دستور سیستمی از مدل بخواهید کوتاه جواب بدهد.

هزینه

هزینهٔ اتصال زنده برای هر نوبت جدا از همان اعتبار API کم می‌شود: فراخوانی مدل یک ردیف است و هر تکهٔ گفتاری پاسخ یک ردیف جدا. همهٔ این ردیف‌ها با برچسب Realtime (WebSocket) و Speech و با هزینهٔ دقیق هر کدام در گزارش درخواست‌های پنل دیده می‌شوند.

در مدل‌های گفتاری مستقیم هر اتصال یک ردیف است: هنگام باز شدن اتصال مبلغی از اعتبار API کنار گذاشته می‌شود، در طول گفت‌وگو هر وقت لازم باشد بیشتر می‌شود و وقتی اتصال بسته شد فقط مصرف واقعی (توکن‌های صدا و متن ورودی و خروجی) کم می‌شود و بقیه آزاد می‌شود. این ردیف بعد از بسته شدن اتصال با برچسب Realtime (WebSocket) در همان گزارش دیده می‌شود. اگر اعتبار در میانهٔ گفت‌وگو تمام شود، پیش از بسته شدن اتصال یک رویداد error با کد insufficient_credit می‌رسد.

حریم خصوصی

صدا و متن گفت‌وگو را ذخیره نمی‌کنیم. مثل هر درخواست دیگر API، از هر نوبت فقط شمار توکن‌ها و هزینه‌اش ثبت می‌شود.

خطاها

پیش از باز شدن اتصال (پاسخ HTTP)

codeHTTPمعنا و راه رفع
missing_api_key401هدر Authorization یا X-API-Key فرستاده نشده.
invalid_api_key401کلید نادرست است.
api_key_revoked401کلید باطل شده، منقضی شده یا غیرفعال است.
ip_not_allowed403IP سرور شما در فهرست IPهای مجاز کلید نیست.
model_not_realtime400مدل ورودی صوتی ندارد؛ یک مدل گفت‌وگوی صوتی (مثل qwen/qwen3.8-omni-flash) انتخاب کنید.
insufficient_credit402اعتبار حساب کافی نیست؛ اعتبار را شارژ کنید.
realtime_session_limit429حساب شما ۱۰ جلسهٔ باز دارد؛ پیش از اتصال تازه یکی را ببندید.
too_many_connections429از یک IP در یک دقیقه بیش از حد اتصال تازه باز شده؛ کمی صبر کنید و دوباره وصل شوید.
invalid_codec400مقدار codec یکی از alaw، ulaw، pcm8، pcm16 یا pcm24 نیست.

در طول جلسه (رویداد error)

رویداد خطا
{"type": "error", "error": {"type": "invalid_request_error", "code": "conversation_already_has_active_response", "message": "…", "param": null, "event_id": "evt_…"}}
codeمعنا و راه رفع
unsupported_eventنوع رویداد پشتیبانی نمی‌شود (فهرست رویدادهای کلاینت را ببینید).
invalid_audio_formatقالب صوتی در session.update معتبر نیست.
input_audio_buffer_commit_emptyبافر خالی را commit کرده‌اید.
input_audio_buffer_too_largeیک نوبت گفتار از ۶۰ ثانیه بیشتر شده.
audio_rate_exceededصوت سریع‌تر از چهار برابر زمان واقعی فرستاده شده.
conversation_already_has_active_responseپاسخ قبلی هنوز تمام نشده؛ صبر کنید یا response.cancel بفرستید.
speech_failedتبدیل یک تکه از پاسخ به گفتار ناموفق بود؛ متن آن در transcript هست.
session_closedجلسه بسته شد (یک ساعت گذشته، ۱۲۰ ثانیه پیامی نیامده، یا کلید باطل شده).
server_restartسرویس در حال به‌روزرسانی است؛ چند ثانیه بعد دوباره وصل شوید.

فهرست کامل کدهای خطای API در صفحهٔ خطاها است.