https://api.echonova.aiالمطورون
الأخطاء
كل حالة HTTP وكل errorMessage تعيدها واجهة API الإصدار v1، ومتى يحدث كل منها، وما الذي تفعله حياله، وكيف تبلغ المهام غير المتزامنة عن فشلها.
تسرد هذه الصفحة كل خطأ تعيده نقاط النهاية في /v1: رمز HTTP،
وerrorMessage بالنص الحرفي، والشرط الذي يطلقه، والإصلاح. وهي للمهندس الذي
يكتب فرع معالجة الأخطاء في عميله. أما أخطاء المهام غير المتزامنة، فليست أخطاء
HTTP، وهي في آخر الصفحة.
شكل استجابة الخطأ
كل خطأ كائن JSON واحد، يحمل الحقول الأربعة نفسها التي تحملها الاستجابة الناجحة.
قيمة success هي false، وقيمة data هي null، وstatusCode يكرر رمز HTTP،
وerrorMessage هو النص المقتبس في الجداول أدناه.
يحمل كل خطأ على مسار /v1 أيضًا الحقل docs، وهو رابط إلى هذه الصفحة. أما 401 فيرتبط بصفحة المصادقة بدلًا منها.
{
"data": null,
"statusCode": 400,
"success": false,
"errorMessage": "text must be shorter than or equal to 500 characters",
"docs": "https://echonova.ai/docs/developers/errors"
}عندما تفشل عدة قواعد تحقق في طلب واحد، تُدمج رسائلها في errorMessage واحد،
مفصولة بفاصلة ومسافة. طابق الرمز أولًا، ثم الرسالة. الرسالة نص عادي وليست رمزًا،
وأي تغيير فيها مذكور في سجل التغييرات.
المصادقة
يُرفض الطلب قبل تشغيل نقطة النهاية. كل 401 يحمل الرسالة نفسها، فلا يخبرك النص
أي الأسباب الخمسة هو السبب. ترتيب الفحوص كاملًا في المصادقة.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
401 |
Unauthorized |
لا يوجد header باسم Authorization، أو المخطط ليس Bearer، أو الرمز لا يبدأ بـ ek_. |
أرسل Authorization: Bearer ek_.... |
401 |
Unauthorized |
لا يطابق الرمز أي مفتاح: المفتاح مكتوب بخطأ أو غير معروف. | قارن المفتاح بأول 8 أحرف منه في البوابة. |
401 |
Unauthorized |
حُذف المفتاح. | أنشئ مفتاحًا جديدًا. |
401 |
Unauthorized |
المفتاح معطّل. | فعّله من المطورون، ثم مفاتيح واجهة برمجة التطبيقات. |
401 |
Unauthorized |
الحساب الذي يملك المفتاح مغلق. | أرسل Authorization: Bearer ek_... بمفتاح مفعّل. |
403 |
Subscription not found |
مساحة العمل التي تملك المفتاح ليس لها اشتراك. | تحقّق من خطة مساحة العمل في البوابة. |
403 |
Subscription expired or inactive |
الاشتراك في حالة غير النشطة والتجريبية. | جدّد الاشتراك. |
403 |
This API key does not have access to Text-to-Speech services |
المفتاح مقيّد، و«تحويل النص إلى كلام» ليست من خدماته. يعمل الفحص على كل مسار تحت /v1/text-to-speech، بما فيها قائمة الأصوات. |
تعديل المفتاح ومنحه «تحويل النص إلى كلام»، أو استخدم مفتاحًا آخر. |
403 |
This API key does not have access to Speech-to-Text services |
المفتاح مقيّد، و«تحويل الكلام إلى نص» ليست من خدماته. | تعديل المفتاح ومنحه «تحويل الكلام إلى نص»، أو استخدم مفتاحًا آخر. |
403 |
This API key does not have access to Sound Cleaning services |
المفتاح مقيّد، و«تنقية الصوت» ليست من خدماته. | تعديل المفتاح وتفعيل «تنقية الصوت»، أو استخدم مفتاحًا آخر. |
حد معدل الطلبات وحد الرصيد والرصيد
يعيد خطآن مختلفان الرمز 429. اقرأ errorMessage قبل إعادة المحاولة: أحدهما
يزول مع الوقت، والآخر لا يزول.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
429 |
ThrottlerException: Too Many Requests |
أرسل المفتاح أكثر من 100 طلب إلى نقطة نهاية واحدة خلال 60 ثانية. يحمل header باسم Retry-After عدد الثواني للانتظار. يُطبَّق حد بالحجم نفسه على كل عنوان IP للعميل، للطلبات التي يرفضها فحص المفتاح فقط. ويعيد الاستجابة نفسها حتى عندما يكون المفتاح مفقودًا أو غير صالح. |
انتظر ثواني Retry-After، ثم أعد المحاولة. راجع حد معدل الطلبات. |
429 |
Monthly spending limit exhausted |
يتجاوز الطلب حد الرصيد للمفتاح في دورة الفوترة هذه. يُرفض قبل تشغيل الطلب في كل طلب يُحتسب: نقطتا تحويل النص إلى كلام، ونقطتا تحويل الكلام إلى نص، و«تنقية الصوت». لم يُنفَّذ شيء. لا يوجد header Retry-After. |
ارفع الحد أو أزله من المفتاح، أو انتظر الدورة التالية. راجع الرصيد. |
402 |
Insufficient subscription balance |
رصيد مساحة العمل لا يغطي تكلفة هذا الطلب. لم يُنفَّذ شيء، ولم يُحتسب أي رصيد. | أضف رصيدًا إلى مساحة العمل. |
التحقق من الطلب
يرفض التحقق من الجسم أو المعاملات هذه الأخطاء قبل تنفيذ أي عمل. لا يُحتسب أي رصيد. تُقصّ المسافات البيضاء في بداية كل نص ونهايته قبل فحص هذه القواعد، وتُرفض الحقول غير المعرّفة.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
400 |
text must be longer than or equal to 1 characters, text should not be empty |
text نص فارغ أو يحتوي مسافات فقط. |
أرسل حرفًا واحدًا على الأقل غير مسافة. |
400 |
text must be shorter than or equal to 500 characters, text must be longer than or equal to 1 characters, text should not be empty, text must be a string |
text غائب أو null. تفشل كل قواعد الحقل معًا. |
أرسل text كنص JSON. |
400 |
text must be shorter than or equal to 500 characters, text must be longer than or equal to 1 characters, text must be a string |
text رقم أو قيمة منطقية أو كائن. |
أرسل text كنص JSON. |
400 |
text must be shorter than or equal to 500 characters |
text تجاوز الحد في نقطتي تحويل النص إلى كلام. |
قسّم النص إلى عدة طلبات. |
400 |
voiceId should not be empty, voiceId must be a string |
voiceId غائب أو null. |
أرسل id من GET /v1/text-to-speech/voices. |
400 |
voiceId should not be empty |
voiceId نص فارغ. |
أرسل id من استدعاء الأصوات. |
400 |
speed must not be less than 0.5 or speed must not be greater than 2 |
speed رقم خارج النطاق. |
ابقَ ضمن النطاق في أصوات تحويل النص إلى كلام وخياراته. |
400 |
cfg must not be less than 1 or cfg must not be greater than 5 |
cfg رقم خارج النطاق من 1 إلى 5. |
أرسل cfg من 1 إلى 5. |
400 |
speed must not be greater than 2, speed must not be less than 0.5, speed must be a number conforming to the specified constraints |
speed ليس رقمًا في JSON، مثل النص "1". |
أرسل رقمًا، لا نصًا. |
400 |
cfg must not be greater than 5, cfg must not be less than 1, cfg must be a number conforming to the specified constraints |
cfg ليس رقمًا في JSON، مثل النص "1". |
أرسل رقمًا، لا نصًا. |
400 |
numSteps must be one of the following values: 16, 32, 48, 64, 128 |
numSteps قيمة غير القيم الخمس. |
أرسل إحدى القيم الخمس. |
400 |
tashkeel must be a boolean value |
tashkeel ليس true ولا false. |
أرسل قيمة منطقية في JSON. |
400 |
property <name> should not exist |
يحمل الجسم أو الاستعلام حقلًا لا تعرّفه نقطة النهاية، مثل حقل من نسخة أقدم. | احذف الحقل. |
400 |
offset must not be less than 0 |
offset في قائمة المهام سالب. |
أرسل 0 أو أكثر. |
400 |
offset must be an integer number |
offset ليس عددًا صحيحًا. |
أرسل عددًا صحيحًا. |
400 |
limit must not be less than 1 or limit must not be greater than 100 |
limit في قائمة المهام خارج النطاق. |
أرسل من 1 إلى 100. |
400 |
limit must not be greater than 100, limit must not be less than 1, limit must be an integer number |
limit ليس رقمًا أصلًا. |
أرسل عددًا صحيحًا من 1 إلى 100. |
400 |
Invalid identifier |
voiceId ليس معرّفًا سليم التكوين، أو jobId ليس من 24 خانة سداسية عشرية. |
انسخ المعرّف كما أعادته الواجهة تمامًا. |
400 |
Request body is not valid JSON |
لا يمكن تحليل جسم JSON، مثلًا لأن فيه فاصلة زائدة. يُرفض قبل فحص المفتاح، فلا يحصل على صف في النشاط. | أرسل JSON صالحًا. |
413 |
Request body is larger than 100 KB |
جسم JSON أكبر من 100 كيلوبايت. يُرفض قبل فحص المفتاح، فلا يحصل على صف في النشاط. لرفع الملفات حدها الخاص، راجع الرفع. | أرسل جسمًا أصغر. |
415 |
Content-Type must be application/json |
أُرسل جسم إلى POST /v1/text-to-speech أو POST /v1/text-to-speech/sync أو تذكرة ودجت بـ Content-Type غير JSON. يُفحص المفتاح أولًا، فيُسجَّل الطلب. |
أرسل Content-Type: application/json. |
الرفع
تُطلق هذه الأخطاء على POST /v1/speech-to-text وPOST /v1/speech-to-text/sync
وPOST /v1/sound-cleaning أثناء استلام الملف أو فحصه. لا يُحتسب أي رصيد. ينطبق
صفوف language وnumbers_as_digits وidentify_speakers على نقطتي تحويل الكلام إلى نص فقط.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
413 |
File too large |
الرفع أكبر من 150 ميجابايت. يُقطع الطلب قبل قراءة الملف. | أعد ترميز الملف بمعدل بت أقل، أو بقناة واحدة (mono). |
400 |
Multipart: Boundary not found |
يحمل header Content-Type القيمة multipart/form-data دون حدّ (boundary). يحدث هذا عندما يضبط العميل header بيده بدلًا من أن يتركه أداة الإرسال تضبطه. |
احذف header الذي كتبته بيدك، ودع العميل يضبطه مع الحد. |
400 |
Unexpected file field - <name> |
اسم جزء الملف غير file. |
سمِّ الجزء file. |
400 |
File is required |
لا يحتوي النموذج على جزء ملف، أو أن الطلب ليس multipart أصلًا، مثل جسم JSON أو جسم ملف خام. | أرسل نموذج multipart بجزء واحد اسمه file. |
400 |
Unsupported file type: <type>. Please upload an audio file. |
لا يبدأ Content-Type للجزء بـ audio/. يمثّل <type> ما أرسله عميلك، وtext/plain يعني أنه لم يرسل نوعًا. |
اضبط نوع الجزء، مثل audio/wav أو audio/mpeg. راجع تنسيقات تحويل الكلام إلى نص ومخرجاته. |
400 |
Audio exceeds the 10-minute limit. |
مدة الملف تتجاوز الحد على نقطة تحويل الكلام إلى نص أو تنقية الصوت. | قسّم التسجيل إلى أجزاء مدة كل منها 10 دقائق أو أقل. |
400 |
Could not read the audio length. Try another file. |
الملف فارغ، أو تعذّر فكّ ترميزه كصوت. | تحقّق من أن الملف يُشغَّل، أو صدّره مرة أخرى بصيغة شائعة. |
503 |
Audio processing is temporarily unavailable. Please try again. |
عُرضت عدة ملفات للقياس في وقت واحد، أو انتهت مهلة القياس. لم يُحتسب أي رصيد. | أعد المحاولة بعد انتظار قصير. |
400 |
language must be one of: auto, ar, en |
يحمل حقل النموذج language قيمة غير auto أو ar أو en، مع تجاهل حالة الأحرف والمسافات حول القيمة، مثل en-US أو arabic. |
أرسل auto أو ar أو en، أو اترك الحقل. راجع تنسيقات تحويل الكلام إلى نص ومخرجاته. |
400 |
numbers_as_digits must be true or false |
حقل النموذج numbers_as_digits ليس true أو false أو 1 أو 0. |
أرسل true أو false، أو اترك الحقل. |
400 |
identify_speakers must be true or false |
حقل النموذج identify_speakers ليس true أو false أو 1 أو 0. |
أرسل true أو false، أو اترك الحقل. انظر صيغ تحويل الكلام إلى نص ومخرجاته. |
تنقية الصوت
تُطلق هذه الأخطاء على POST /v1/sound-cleaning، إضافةً إلى أخطاء الرفع أعلاه.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
400 |
Unsupported audio format. Sound cleaning accepts MP3, WAV, FLAC or OGG/Opus. |
امتداد الملف أو Content-Type ليس واحدًا من الصيغ الأربع، أو أن الاثنين لا يتطابقان. |
أرسل MP3 أو WAV أو FLAC أو OGG/Opus، مع امتداد ونوع متطابقين. |
400 |
targetLufs must not be greater than -6 |
حقل ضبط خارج نطاقه. تسمّي الرسالة الحقل والحد. | ابقَ ضمن الحد الأدنى والأقصى المذكورين للحقل. |
503 |
Sound cleaning is temporarily unavailable. Please try again. |
تعذّر الوصول إلى أداة التنقية. يُسترد الرصيد المحتسب. | أعد المحاولة مرة واحدة. |
غير موجود
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
404 |
Route not found |
لا توجد نقطة نهاية بهذا المسار. لا تكرر الرسالة المسار. لا يُسجَّل في النشاط. | قارن المسار، ومعه البادئة /v1، بصفحة نقطة النهاية. |
405 |
Method not allowed |
المسار موجود، لكن ليس بهذه الطريقة. يذكر header باسم Allow الطرق التي يقبلها، مثل GET, HEAD. لا يُسجَّل في النشاط. |
أرسل الطلب بطريقة من Allow. |
404 |
Voice not found |
لا يوجد صوت نشط بهذا voiceId. الصوت الذي سُحب يختفي من القائمة. |
أعد عرض الأصوات واختر واحدًا. |
404 |
TTS Job not found |
معرّف المهمة غير معروف، أو أن المهمة تخص مساحة عمل أخرى، أو أنها أُنشئت من البوابة. | استخدم jobId من مهام API في مساحة العمل هذه. |
404 |
STT Job not found |
كالسابق، لمهام تحويل الكلام إلى نص. | استخدم jobId من مهام API في مساحة العمل هذه. |
404 |
Clean Job not found |
كالسابق، لمهام تنقية الصوت. | استخدم jobId من مهام API في مساحة العمل هذه. |
تأتي الرسائل الثلاث 404 نفسها من GET وDELETE على المهمة، وتأتي STT Job not found أيضًا من تنزيلها. يحذف المفتاح مهام
API في مساحة عمله، أيًّا كان المفتاح الذي أنشأها، فالمهمة التي تخص مساحة عمل أخرى
ترد 404.
حذف المهام
تُطلق هذه الأخطاء على DELETE /v1/text-to-speech/jobs/{jobId}،
وDELETE /v1/speech-to-text/jobs/{jobId}، وDELETE /v1/sound-cleaning/jobs/{jobId}.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
400 |
Job is still processing |
المهمة في حالة pending أو processing. لا تُحذف إلا مهمة مكتملة أو فاشلة. |
انتظر حتى تنتهي المهمة، ثم احذفها. |
503 |
The stored file could not be deleted. Try again. |
تعذّرت إزالة الملف الصوتي المخزّن للمهمة. تبقى المهمة. | أعد الحذف بعد انتظار قصير. |
تنزيل النصوص المفرّغة
تُطلق هذه الأخطاء على GET /v1/speech-to-text/jobs/{jobId}/export، إضافةً إلى
أخطاء المصادقة وحد معدل الطلبات والخدمة، وInvalid identifier،
وproperty <name> should not exist، وSTT Job not found أعلاه. لا يُحتسب أي
رصيد مقابل التنزيل. النجاح هو الملف نفسه، أما الخطأ فهو كائن الخطأ المعتاد.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
400 |
format must be one of the following values: txt, srt, json |
معامل الاستعلام format مفقود، أو ليس txt أو srt أو json، مثل vtt. |
أرسل format=txt أو format=srt أو format=json. |
400 |
lang must be one of the following values: en, ar |
معامل الاستعلام lang يحمل قيمة غير en أو ar. |
أرسل lang=en أو lang=ar، أو احذفه لتكون en. |
400 |
Job is not completed |
المهمة في حالة pending أو processing أو failed. لا يوجد نص مفرّغ للتنزيل إلا في المهمة المكتملة. |
انتظر Webhook job.completed، أو استعلم دوريًا عن GET /v1/speech-to-text/jobs/{jobId} حتى يصبح status هو completed. |
تذاكر الودجت
تظهر عند استدعاء POST /v1/widgets/{publicId}/tickets. إصدار التذكرة مجاني. لا يُخصم أي رصيد.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
400 |
ttlSeconds must not be less than 60 |
ttlSeconds خارج النطاق من 60 إلى 900 أو ليس عددًا صحيحًا. تسمّي الرسالة الحد. |
أرسل عددًا صحيحًا من الثواني بين 60 و900، أو اترك الحقل لتحصل على 300. |
400 |
channel must be one of the following values: voice, chat |
channel أي قيمة أخرى. |
أرسل voice أو chat، أو اترك الحقل. |
400 |
user.id must be shorter than or equal to 128 characters |
user.id أطول من 128 حرفًا. |
أرسل user.id بطول 128 حرفًا أو أقل. |
400 |
user.id must be longer than or equal to 1 characters |
user.id نص فارغ. |
أرسل user.id غير فارغ، أو اترك الحقل. |
400 |
user.id must not contain control characters |
user.id يحمل محرف تحكم مثل سطر جديد أو tab. |
أزل محارف التحكم من user.id. |
400 |
user.name must be shorter than or equal to 80 characters |
user.name أطول من 80 حرفًا. |
أرسل user.name بطول 80 حرفًا أو أقل. |
403 |
This API key does not have access to Agents |
المفتاح مقيّد، و«الوكلاء» ليست من خدماته. | عدّل المفتاح وفعّل «الوكلاء»، أو استخدم مفتاحًا آخر. |
404 |
widget_not_found |
لا يوجد ودجت بهذا publicId، أو أن الودجت يخص مساحة عمل أخرى. |
انسخ publicId من إعدادات الودجت لوكيل في مساحة العمل هذه. |
409 |
widget_not_private |
الودجت في الوضع العام، ولا يحتاج إلى تذكرة. | حوّل الودجت إلى الوضع الخاص من إعداداته. |
409 |
widget_disabled |
الودجت متوقف، فلا تستطيع أي تذكرة بدء جلسة. | شغّل الودجت من إعداداته. |
أخطاء الخدمة
تُطلق أثناء بدء التوليد والتفريغ النصي، سواء في الاستدعاءات المتزامنة أو عند بدء الاستدعاءات غير المتزامنة. عندما لا تُقبل العملية، يُسترد الرصيد المحتسب، ويفشل الطلب بأحد هذه الأخطاء.
| الحالة | errorMessage |
متى | الإصلاح |
|---|---|---|---|
503 |
Speech generation is temporarily unavailable. Please try again. |
توليد الكلام غير متاح للطلب. عند POST /v1/text-to-speech تظهر المهمة بالحالة failed، ولا يُرسَل Webhook. |
أعد المحاولة بعد انتظار قصير. |
503 |
Transcription is temporarily unavailable. Please try again. |
التفريغ النصي غير متاح للطلب، أو، عند POST /v1/speech-to-text/sync، تعذّر فكّ ترميز الملف. عند POST /v1/speech-to-text تظهر المهمة بالحالة failed، ولا يُرسَل Webhook. |
أعد المحاولة مرة واحدة. إذا فشل الملف نفسه في كل مرة، فأرسله إلى POST /v1/speech-to-text، لأن مهمته تحمل السبب في error. |
400 |
Cloned voices work with instant generation only for now. |
أُرسل صوت مستنسخ إلى POST /v1/text-to-speech، وهذه النقطة لا تدعمه. |
استخدم POST /v1/text-to-speech/sync للأصوات المستنسخة. |
400 |
نص حر للسبب، 300 حرف كحد أقصى | رفض الطلب لسبب خاص به. نادر. | اقرأ الرسالة وأصلح الطلب. |
500 |
Something went wrong |
خطأ لم تصنّفه الواجهة. | تحقّق من الطلب. أعد المحاولة بعد انتظار قصير، وتواصل مع الدعم إذا استمر الخطأ. |
503 |
Database unavailable |
انقطاع عابر داخل الواجهة. | أعد المحاولة بعد انتظار قصير. |
504 |
Database timed out |
انتهاء مهلة عابر داخل الواجهة. | أعد المحاولة بعد انتظار قصير. |
أخفاق المهام غير المتزامنة
لا تعيد المهمة غير المتزامنة التي تفشل بعد قبولها خطأ HTTP. تصبح status للمهمة
failed، ويحمل حقل error السبب، ويُسترد الرصيد، وتُرسَل في معظم الحالات Webhook
باسم job.failed. ويحتفظ creditsConsumed بالمبلغ الذي حُسب.
error على المهمة |
متى | Webhook job.failed |
|---|---|---|
| سبب نصي عادي | فشلت المهمة وأُعطي سبب. | تُرسَل. |
AI server generation failed |
فشلت مهمة تحويل النص إلى كلام دون إعطاء سبب. | تُرسَل. |
AI server transcription failed |
فشلت مهمة تحويل الكلام إلى نص دون إعطاء سبب. | تُرسَل. |
Job timed out — AI server did not respond |
بقيت المهمة في processing أكثر من 10 دقائق دون نتيجة. تتحول الحالة إلى failed خلال 15 دقيقة من POST. |
لا تُرسَل. |
errorMessage الخاص بالرمز 503 أعلاه |
لم تُقبل المهمة عند الإرسال. أعاد POST نفسه الرمز 503. |
لا تُرسَل. |
لا ترسل المهلة أي Webhook، فالعميل الذي ينتظر job.completed أو job.failed فقط
لن يعرف عنها أبدًا. استخدم الاستعلام الدوري عبر GET /v1/text-to-speech/jobs/{jobId}
أو GET /v1/speech-to-text/jobs/{jobId} إذا لم يصل أي حدث بعد 15 دقيقة من POST.
أجسام الأحداث موجودة في أحداث Webhook.
نماذج الكود
اقرأ الحالة، ثم errorMessage. أعد المحاولة فقط عند 429 الخاص بحد معدل الطلبات،
بعد ثواني Retry-After، وعند الأخطاء 503 و504. أي إعادة محاولة تُنشئ مهمة
ثانية مذكورة في أعد المحاولة بأمان.
curl -s -o response.json -w "%{http_code}" \
-X POST "https://api.echonova.ai/v1/text-to-speech/sync" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "", "voiceId": "VOICE_ID"}'
# prints 400; response.json holds "text must be longer than or equal to 1 characters, text should not be empty"import time
import requests
response = requests.post(
"https://api.echonova.ai/v1/text-to-speech/sync",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"text": "", "voiceId": "VOICE_ID"},
)
body = response.json()
if not body["success"]:
message = body["errorMessage"]
if response.status_code == 429 and "Retry-After" in response.headers:
time.sleep(int(response.headers["Retry-After"]))
# retry the request
elif response.status_code in (503, 504):
time.sleep(5)
# retry the request
else:
raise RuntimeError(f"{response.status_code}: {message}")const response = await fetch('https://api.echonova.ai/v1/text-to-speech/sync', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: '', voiceId: 'VOICE_ID' }),
});
const body = await response.json();
if (!body.success) {
const retryAfter = response.headers.get('Retry-After');
if (response.status === 429 && retryAfter) {
await new Promise((r) => setTimeout(r, Number(retryAfter) * 1000));
// retry the request
} else if (response.status === 503 || response.status === 504) {
await new Promise((r) => setTimeout(r, 5000));
// retry the request
} else {
throw new Error(`${response.status}: ${body.errorMessage}`);
}
}الأسئلة الشائعة
أي الأخطاء آمن لإعادة المحاولة؟
الرمز 429 الخاص بحد معدل الطلبات، بعد ثواني Retry-After، وكل 503 و504.
أما 400 و401 و403 و404 و402 فتعيد الجواب نفسه حتى تغيّر الطلب أو المفتاح
أو الرصيد. أي إعادة محاولة تُنشئ مهمة ثانية مذكورة في
أعد المحاولة بأمان.
هل يُحتسب شيء عند ظهور خطأ؟
لا. كل خطأ مذكور أعلاه يُطلق قبل الاحتساب، أو يُسترد الرصيد قبل إعادة الخطأ.
لماذا يوجد استجابتان بالرمز 429؟
الأولى لحد معدل الطلبات، وتزول مع الوقت، وتحمل Retry-After. والثانية هي حد الرصيد
للمفتاح، ولا تزول إلا عندما ترفع الحد أو تبدأ دورة الفوترة التالية، ولا تحمل أي header.
فرّق بينهما من خلال errorMessage.
لماذا تقول كل استجابة 401 الشيء نفسه؟
تغطي Unauthorized header مفقودًا أو مشوّهًا، ومفتاحًا غير معروف، ومفتاحًا محذوفًا،
ومفتاحًا معطّلًا، وحسابًا مغلقًا. تحقّق من header أولًا، ثم من الحالة للمفتاح تحت
المطورون، ثم مفاتيح واجهة برمجة التطبيقات.
هل أطابق errorMessage في الكود؟
نعم، بعد مطابقة الرمز أولًا. الرسائل نص عادي، وأي تغيير فيها مذكور في سجل التغييرات.