تعمل الواجهة البرمجية مع الوكلاء والمكالمات والرصيد (Credits) نفسها الموجودة في لوحة التحكم على الويب. كل ما تبنيه في لوحة التحكم يمكن التحكم به من أنظمتك الخاصة، والعكس صحيح.
| ماذا | نقطة النهاية |
|---|---|
| عرض الوكلاء | GET /api/v1/voice/agents |
| إنشاء وكيل | POST /api/v1/voice/agents |
| جلب وكيل / تحديثه | GET · PATCH /api/v1/voice/agents/{id} |
| إجراء مكالمة صادرة | POST /api/v1/voice/calls |
| عرض المكالمات | GET /api/v1/voice/calls |
| جلب مكالمة (النص المفرَّغ) | GET /api/v1/voice/calls/{id} |
| حذف مكالمة | DELETE /api/v1/voice/calls/{id} |
| حذف مكالمات متصل | POST /api/v1/voice/calls/delete-by-caller |
| الحملات | GET · POST /api/v1/voice/campaigns |
| جلب حملة | GET /api/v1/voice/campaigns/{id} |
| بدء / إيقاف مؤقت / إلغاء | POST /api/v1/voice/campaigns/{id}/{action} |
| الأصوات المستنسخة | GET · POST /api/v1/voice/voices |
| حذف صوت مستنسخ | DELETE /api/v1/voice/voices/{id} |
| قائمة عدم الاتصال | GET · POST /api/v1/voice/do-not-call |
| الإزالة من القائمة | DELETE /api/v1/voice/do-not-call/{phone} |
| اللغات والأصوات والقوالب | GET /api/v1/voice/catalog |
| اختبارات الوكيل | GET · POST /api/v1/voice/agents/{id}/tests |
| تشغيل الاختبارات / قراءة تشغيل | POST /api/v1/voice/agents/{id}/test-runs · GET /api/v1/voice/test-runs/{id} |
| توجيه رقم إلى وكيل | PATCH /api/v1/voice/phone-numbers/{id} |
| قوائم الكلمات | GET · POST /api/v1/voice/vocabularies |
أنشئ مفتاحًا من التكاملات ← مفاتيح API في لوحة التحكم (أو بنقرة واحدة من النظرة العامة) وأرسله كرمز Bearer:
Authorization: Bearer sk-your-key
يعمل المفتاح في مساحة العمل التي يعمل فيها مالكه، وبصلاحيات دور ذلك الشخص: مفتاح عضو للقراءة فقط يستطيع القراءة لكنه لا يغيّر شيئًا.
أنشئ وكيلًا من قالب، ويمكنك ضبط حقوله في الطلب نفسه. من دون template يبدأ فارغًا؛ ويعرض GET /api/v1/voice/catalog القوالب مع اللغات والأصوات التي يقبلها الوكيل. القوالب مكتوبة بالإنجليزية والصينية، فلأي لغة أخرى أرسل system_prompt وfirst_message بتلك اللغة. إمّا أن يُحفظ الطلب كله وإمّا ألّا يُنشأ أي وكيل، لذا يمكن إعادة إرسال الطلب المرفوض بعد تصحيحه. والحقل dashboard_url في الرد هو صفحة الوكيل في لوحة التحكم، حيث تتحدث مع المسودة من المتصفح. يعمل كل وكيل على EvaSay ASR وEvaSay LLM وEvaSay TTS، وتختارها EvaSay لكل مكالمة بحسب لغتها والحِمل، وهي مشمولة في سعر المكالمة؛ فلا توجد حسابات لمزوّدين آخرين تحتاج إلى إعدادها.
curl https://evasay.com/api/v1/voice/agents \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Front desk",
"language": "en",
"first_message": "Hi, thanks for calling Sunrise Salon. How can I help?",
"system_prompt": "You are the front desk of Sunrise Salon..."
}'
حدّث أيًّا من هذه الحقول عبر PATCH /api/v1/voice/agents/{id}:
| الحقل | ملاحظات |
|---|---|
name, first_message, system_prompt | نص |
status | published ينشر المسوّدة كإصدار جديد؛ وdraft يوقف استقبال المكالمات |
language | إحدى 27 لغة، مثل en وzh وes وde، أو multi لمتابعة لغة المتصل |
temperature | 0-100 |
max_duration_sec, silence_timeout_sec | حدود المكالمة |
interruptible, end_call_enabled | قيم منطقية |
confirm_details | قيمة منطقية؛ يكرّر الأرقام والأسماء بصوت عالٍ ويطلب تأكيدها |
ai_disclosure | قيمة منطقية، الافتراضي true؛ قبل رسالته الأولى يقول الوكيل بلغة المكالمة إن المتصل يتحدث مع ذكاء اصطناعي (يُحذف عندما تقول الرسالة الأولى ذلك أصلًا) |
voicemail_detection | قيمة منطقية؛ المكالمات الصادرة تستمع أولًا وتنتهي عند الوصول إلى بريد صوتي |
voicemail_message | تُترك في البريد الصوتي، ويمكن أن تستخدم {{variables}}؛ وبدونها يُغلق الخط |
transfer_number | الرقم المراد التحويل إليه، بالصيغة الدولية |
transfer_destinations | حتى 9 أرقام إضافية، [{name, number, when}]؛ يختار الوكيل واحدًا بحسب when |
transfer_briefing | قيمة منطقية؛ يسمع أول من يرد ملخص الوكيل للمكالمة |
pronunciations | حتى 100 عنصر [{word, say, case_sensitive}]؛ ينطق الصوت say بدل word |
idle_messages | حتى 3 تذكيرات تُقال بالتتابع لمتصل صامت قبل أن تنتهي المكالمة |
noise_reduction | قيمة منطقية؛ تُرشَّح ضوضاء خلفية المتصل قبل أن تُسمع |
recording_enabled | قيمة منطقية؛ تُسجَّل المكالمات في قناتين (المتصل على اليسار والوكيل على اليمين) |
recording_consent | announce أو ask (يُحتفظ بالتسجيل فقط إذا وافق المتصل) أو none |
recording_notice | الإشعار أو السؤال الذي يُقال أولًا؛ فارغ لاستخدام النص المدمج بلغة المكالمة |
handoffs | حتى 5 عناصر [{agent_id, when}]: وكلاء آخرون يجوز لهذا الوكيل تسليمهم مكالمة |
knowledge_base_id | إحدى قواعد معرفتك |
vocabulary_id | أحد قواميسك؛ تُميَّز مصطلحاته بموثوقية أكبر حين ينطقها المتصل |
voice_id | معرّف صوت EvaSay مدمج، أو أحد أصواتك المستنسخة (clone:…) |
تعتمد الأصوات المدمجة على اللغة: للصينية ming-designed-female-clear وming-designed-female-warm (نسائية) وming-designed-male-clear وming-designed-male-friendly (رجالية)، وللغات الأخرى F1–F5 (نسائية) وM1–M5 (رجالية). الصوت المدمج الذي لا يتحدث لغة الوكيل يُستبدل بصوت من الجنس نفسه يتحدثها. ما زال اسم الحقل القديم tts_voice_id مقبولًا. تُرفض أي قيمة أخرى لـ voice_id، وكذلك الصوت المستنسخ الذي لم يجهز بعد.
يحدد analysis_config ما يُستخلص من كل مكالمة بعد انتهائها: summary (الافتراضي true)، وsummaryLanguage، وsuccessCriteria (ما تحققه المكالمة الناجحة)، وfields (حتى 20 من {name, type, description} لاستخراجها، ويكون type إما string أو number أو boolean)، وscorecard (حتى 10 من {name, description, weight}، والوزن من 1 إلى 5). تظهر النتائج في analysis المكالمة وفي webhook call.analyzed.
تغيير حقول وكيل يغيّر مسوّدته. تستمر المكالمات في استخدام الإصدار المنشور إلى أن تنشر المسوّدة عبر POST /api/v1/voice/agents/{id}/publish (ويمكن إضافة note)، أو عبر status: "published" في الطلب PATCH نفسه. كل نشر يحتفظ بإصدار مرقَّم؛ ويوضح published_version في الوكيل أيَّ إصدار تستخدمه المكالمات. تبقى المكالمة على الإصدار الذي كان مباشرًا عند بدئها، لذا فالنشر أثناء المكالمة لا يغيّرها. تستخدم المكالمات التجريبية من لوحة التحكم المسوّدة.
يعرض GET /agents/{id}/versions الإصدارات، ويتراجع POST /agents/{id}/versions/{version}/restore: تستخدم المكالمات الجديدة ذلك الإصدار وتصبح المسوّدة هي هو. أما اسم الوكيل ونشره ومظهر الودجت والإشعارات فلا إصدارات لها وتتغير فورًا، وكذلك مستندات قاعدة معرفته.
يُجري الاختبار مكالمة واحدة نصيًا: يؤدي متصل محاكى دور scenario، ويجيب الوكيل من مسودته (التعليمات والرسالة الأولى والمعرفة)، ويحكم مُقيّم على المحادثة وفق success_criteria. اكتب اختبارات للمكالمات المهمة، وشغّلها بعد كل تغيير، وانشر عندما تنجح.
curl https://evasay.com/api/v1/voice/agents/AGENT_ID/tests \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Move a booking",
"scenario": "A regular customer wants to move Friday 3 pm to Saturday morning.",
"success_criteria": "Offers Saturday times and confirms the new time and the customer'"'"'s name.",
"max_turns": 8
}'
يشغّل POST /agents/{id}/test-runs جميع اختبارات الوكيل، أو تلك الموجودة في test_ids، ويرد بتشغيل واحد لكل اختبار (status: "running"). استعلم عن GET /test-runs/{id} حتى تصبح status إحدى القيم passed أو failed أو error؛ عندها يحتوي التشغيل على transcript وreason الخاص بالمُقيّم (بالإنجليزية، أو بالصينية مع reason_language: "zh"). كل تشغيل يكلّف Credits تظهر بجانب الاختبارات في لوحة التحكم؛ وتتوقف التشغيلات عند أول تشغيل لا يغطيه الرصيد، ويعرض not_started البقية. ويُسترد ثمن التشغيل الذي تعذّر إجراؤه. تتحقق الاختبارات مما يقوله الوكيل، لا من صوته أو توقيته، ولا تستدعي دواله: جرّبها مسبقًا عبر POST /tools/{id}/test. للوكيل حتى 30 اختبارًا؛ ويعدّل PATCH وDELETE /agents/{id}/tests/{test_id} اختبارًا أو يحذفانه.
إلى جانب المكالمات الكاملة (type: "simulation"، الافتراضي)، يمكن للاختبار أن يتحقق من رد واحد. يأخذ type: "next_reply" الحقل chat_history، أي المحادثة السابقة المنتهية بكلام المتصل ([{role, text}]، حيث role هو caller أو agent)، والحقل success_criteria لرد الوكيل التالي. ويأخذ type: "tool_call" الحقلين chat_history وexpected_tool {name, arguments, match}: يجب أن يستدعي الوكيل name (إحدى دواله، أو end_call أو transfer_call أو handoff_to_agent) مع arguments، وتُقارن القيم بدقة (بعد إزالة المسافات الطرفية ودون تمييز حالة الأحرف) أو حسب المعنى مع match: "judge"؛ وتُتجاهل الوسائط الأخرى التي يمررها. ويعرض transcript الخاص بالتشغيل الدوال التي استدعاها الوكيل في tool_calls.
يقترح POST /agents/{id}/tests/generate اختبارات من مسودة الوكيل: تعليماته ومعرفته ودواله. ويأخذ count (من 1 إلى 10، والافتراضي 5) وtypes وfocus (ما يجب تغطيته) وlanguage (en أو zh للأسماء والمعايير)، ويكلّف Credits بقدر تشغيل واحد، ويعيد مسودات تراجعها ثم ترسلها إلى POST /agents/{id}/tests؛ ومع save: true يحفظها مباشرة.
يفعل hooks شيئًا في لحظة معينة من المكالمة، حتى 10 قواعد: on: "silence" (لم يقل المتصل شيئًا طوال seconds، من 3 إلى 600، منذ أن أنهى الوكيل كلامه؛ مرة واحدة إلى أن يتكلم من جديد)، أو on: "time_elapsed" (بعد seconds من بدء المكالمة، من 10 إلى 3600)، أو on: "call_ending". تنفّذ كل قاعدة (do) حتى 3 من {type: "say", text} و{type: "transfer", destination?} و{type: "end_call", text?} و{type: "tool", name, args?}؛ والقاعدة الخاصة بنهاية المكالمة تشغّل الدوال فقط. المكالمة التي تنهيها قاعدة قيمة ended_reason فيها rule_ended.
في المكالمات الهاتفية تصل المفاتيح التي يضغطها المتصل إلى الوكيل كإجابة منه: ينتهي الإدخال بـ# أو بتوقف لمدة ثانيتين. وفي المكالمات الصادرة يستطيع الوكيل أيضًا الضغط على المفاتيح لتجاوز قائمة الهاتف في شركة.
transfer_number هو الرقم الرئيسي للوكيل لتحويل المتصل إلى إنسان، وهو الرقم الذي يُتصل به عندما ينفد رصيد مساحة العمل. ويضيف transfer_destinations أرقامًا مسمّاة، لكل منها ملاحظة عن وقت استخدامه («الفوترة: أسئلة عن الفواتير والمبالغ المستردة»)، ويختار الوكيل. وعند تفعيل transfer_briefing يكتب الوكيل ملخصًا قصيرًا أثناء التحويل؛ ويسمعه الشخص الذي يرد، بصوت من EvaSay وبلغة ملخصات الوكيل، قبل أن يُوصَل المتصل. وتكون قيمة ended_reason للمكالمة حينها transferred.
بفضل handoffs يستطيع الوكيل تسليم مكالمة إلى وكيل منشور آخر في مساحة عملك، كاستقبالٍ يمرّر حجزًا إلى وكيل حجوزات. يختار الوكيل بحسب when. يتولى الوكيل الآخر المكالمة نفسها بكل ما قيل حتى الآن، ويتحدث بتعليماته وصوته ومعرفته وأدواته وعمليات التسليم الخاصة به. تبقى المكالمة مدرجة ومحلَّلة ومفوترة تحت الوكيل الأول؛ ويدوّن نصها المفرَّغ كل تسليم.
تُوصل الأرقام في لوحة التحكم بحساب مشغّل الاتصالات الخاص بك. يعرضها GET /api/v1/voice/phone-numbers، ويرسل PATCH /api/v1/voice/phone-numbers/{id} مع { "agent_id": "AGENT_ID" } مكالمات الرقم إلى وكيل (نسخته المنشورة)، أو مع "agent_id": null إلى لا أحد؛ ويغيّر label اسمه.
تضم قائمة الكلمات أسماء ومصطلحات يقولها المتصلون وقد يسيء التعرّف على الكلام سماعها، مثل أسماء المنتجات أو الأدوية أو الشوارع. أرسل POST /api/v1/voice/vocabularies مع { "name": "Products", "terms": ["Lumora", "Vantix Pro"] } (حتى 1000 مصطلح بطول 50 حرفًا، أو ابدأ من "preset": "medical" أو "legal")، ثم اضبط vocabulary_id للوكيل. تتوفر GET وPATCH (name، terms) وDELETE /vocabularies/{id}؛ ولا يمكن حذف قائمة يستخدمها وكيل.
لكل رقم قواعد مكالمات في صفحة أرقام الهاتف، وتُطبَّق قبل أن يرد الوكيل: تُرفض الأرقام المحظورة أو بدايات الأرقام (+1555) والمتصلون الذين يخفون أرقامهم دون رد ولا تكلّف شيئًا؛ ويمكن تمرير المتصلين المدرجين في قائمة مباشرةً إلى رقم آخر؛ وعندما لا يستطيع الوكيل الرد (غير منشور، أو لا يوجد worker، أو نفد الرصيد ولا يوجد رقم تحويل) يمكن للمكالمة أن ترنّ على رقم أو تُسمع رسالتك الخاصة. ويمكن لاستعلام البدء (run_at_start) أيضًا أن يردّ المتصل بالإجابة {"reject": true, "message": "..."}: يقول الوكيل الرسالة إن وُجدت ثم يُغلق الخط، وتكون قيمة ended_reason هي rejected.
أجرِ مكالمة واحدة من أحد أرقام الهاتف في مساحة عملك. يحتاج كل طلب إلى Idempotency-Key فريد؛ وإرسال المفتاح نفسه مرة أخرى يُرجع المكالمة نفسها بدل الاتصال مرتين.
curl https://evasay.com/api/v1/voice/calls \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "AGENT_ID",
"to": "+14155550100",
"variables": { "customer_name": "Alex", "order_id": "1234" }
}'
الحقل from مطلوب عندما يكون في مساحة العمل أكثر من رقم هاتف واحد. وتملأ variables العناصر النائبة من نوع {{customer_name}} في الرسالة الأولى للوكيل وفي تعليماته.
يُرجع GET /api/v1/voice/calls/{id} حالة المكالمة ومدتها والرصيد المخصوم وملخصها وتحليلها ونصها المفرَّغ. اعرض المكالمات عبر GET /api/v1/voice/calls?agent_id=&status=&channel=&user_id=&page= (user_id: معرّفك الخاص للشخص، من رمز مكالمة ويب). وturns فيها هو سجل تصحيح المكالمة دورًا بدور: أين ذهب الوقت منذ أن أنهى المتصل كلامه حتى سمع الإجابة، بالملّي ثانية — waitMs (نهاية الكلام) وsttMs (التعرّف) وllmMs (أول كلمة من النموذج، وواحدة إضافية لكل جولة دوال) وttsMs (أول صوت من الصوت) وfirstAudioMs (سماع الإجابة) — مع الدوال المستدعاة والمقاطعات والأخطاء. وتعرضه صفحة المكالمة أيضًا.
مع recording_enabled تُسجَّل كل مكالمة بصيغة WAV ثنائي القناة: المتصل على اليسار والوكيل على اليمين، بمعدل أخذ العينات في المكالمة. مع recording_consent: "announce" يقول الوكيل أولًا إن المكالمة مسجَّلة؛ ومع "ask" يسأل، ولا يُحتفظ بالتسجيل إلا إذا وافق المتصل (عدم الرد يُعدّ رفضًا)؛ ومع "none" لا يُقال شيء. تحقق مما يشترطه القانون في المكان الذي تقيمون فيه أنت ومتصلوك.
تُحفظ التسجيلات في تخزين EvaSay، أو في bucket خاص بك متوافق مع S3 (AWS S3 أو Cloudflare R2 أو Google Cloud Storage أو Supabase أو MinIO) تضبطه من التكاملات ← Webhooks والإشعارات ← تخزين التسجيلات. يرفع الـworker الذي يشغّل المكالمة الملف مباشرة إلى الـbucket. يُرجع GET /api/v1/voice/calls/{id} الحقل recordingUrl صالحًا لمدة ساعة بعد تخزين التسجيل، وrecording.status (recording أو stored أو declined أو failed).
يحذف DELETE /api/v1/voice/calls/{id} مكالمة منتهية مع النص المكتوب والتسجيل (في تخزين EvaSay أو في الحاوية الخاصة بك) والتحليل وسجلات Webhook. تبقى Credits المستخدمة في سجل الأرصدة. المكالمة التي لا يمكن حذفها بعد تُرجع 409 مع code call_not_deletable_yet: لا تزال جارية أو انتهت للتو، أو لا تزال قيد المحاسبة، أو قد يكون تسجيلها لا يزال قيد الرفع، أو عليها Credits لم يغطها رصيدك (أضف Credits أولًا).
عندما يطلب شخص حذف بياناته، يحذف POST /api/v1/voice/calls/delete-by-caller مع { "phone_number": "+14155550123" } كل المكالمات مع هذا الرقم (رقم المتصل في المكالمات الواردة، والرقم المطلوب في الصادرة)، أو مع { "user_id": "..." } كل مكالمات الويب التي حمل رمزها هذا user_id. الرد هو { "deleted": 12, "kept_back": { "settling": 1 }, "more": false }: 200 مكالمة على الأكثر في كل طلب، فكرّر الطلب ما دام more يساوي true، ثم لاحقًا للمكالمات في kept_back. إذا كان الرقم في قائمة عدم الاتصال، يبقى فيها. تقوم لوحة التحكم بالأمر نفسه من المكالمات → حذف بيانات متصل.
أرسل POST /api/v1/voice/calls/{id}/control أثناء جريان المكالمة. يلتقط الـworker الذي يشغّل المكالمة الأمر خلال نحو ثانيتين؛ وتردّ الواجهة بـ202. إذا تعذّر الوصول إلى الـworker الذي يشغّل المكالمة، تردّ الواجهة بـ503 (code call_unreachable) ولا يُنفَّذ الأمر.
type | ما يحدث |
|---|---|
say | يقول الوكيل text بعد جملته الحالية، أو فورًا مع "interrupt": true |
note | يُخبَر الوكيل بـtext (دون نطقه) ويأخذه في الحسبان ابتداءً من ردّه التالي؛ ويدوّنه النص المفرَّغ |
end | يقول الوكيل text إن وُجد، ثم يُغلق الخط؛ والمكالمة الهاتفية بدون text تُغلق فورًا |
وتكون قيمة ended_reason للمكالمة حينها api_ended. وفي صفحة المكالمة في لوحة التحكم عناصر التحكم نفسها.
يُرجع POST /api/v1/voice/calls/{id}/listen (ويمكن إضافة { "channels": 2 }) العنوانَ listen_url الذي يمكنك فتحه خلال دقيقتين. وهو WebSocket: أولًا رسالة JSON هي {"type":"start","sampleRate":8000,"channels":1,"encoding":"pcm_s16le"}، ثم إطارات ثنائية من PCM بدقة 16 بت little-endian بما يسمعه المتصل (الصوتان ممزوجان؛ ومع channels: 2 يكون المتصل على اليسار والوكيل على اليمين). ويُغلق عند انتهاء المكالمة. يأتي الصوت مباشرة من الـworker الذي يشغّل المكالمة، لا عبر مستوى التحكم في EvaSay؛ وزر الاستماع في صفحة المكالمة بلوحة التحكم يستخدم العنوان نفسه.
أرسل صوت مكالمة واستقبله من برنامجك الخاص، مثل نظامك الهاتفي أو تطبيقك. ابدأ المكالمة:
curl https://evasay.com/api/v1/voice/calls/websocket \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "agent_id": "AGENT_ID", "encoding": "pcm_s16le", "sample_rate": 16000 }'
يحمل websocket_url في الرد رمزًا لمرة واحدة ويمكن فتحه خلال 15 دقيقة. قيمة encoding إما pcm_s16le (PCM بدقة 16 بت little-endian بمعدل sample_rate يساوي 8000 أو 16000 أو 24000) أو mulaw (μ-law بتردد 8 كيلوهرتز). ينتقل الصوت في الاتجاهين كإطارات ثنائية بتلك الصيغة، ويُفضَّل أن يكون كل إطار 20 مللي ثانية. أما الإطارات النصية فهي JSON:
| الاتجاه | الرسائل |
|---|---|
| أنت ← EvaSay | {"type":"dtmf","digits":"12#"} ضغطات المفاتيح؛ {"type":"end"} يُغلق الخط؛ {"type":"text","text":"…"} كلمات كتبها المتصل ("input":"button" لرد جرى النقر عليه)؛ {"type":"context","text":"…","key":"cart"} ما يبلّغ عنه تطبيقك (لا يرد الوكيل عليه)؛ {"type":"tool_result","id":"…","result":{…}} (أو "error") إجابة دالة صفحة |
| EvaSay ← أنت | start (مع callId)؛ clear (قاطع المتصل: أسقِط صوت الوكيل الذي لم يُشغَّل بعد)؛ transcript (role وtext وfinal، وinput للكلمات المكتوبة)؛ user_started_speaking وuser_stopped_speaking وagent_started_speaking وagent_stopped_speaking؛ cards (cards وquick_replies)؛ tool (id وname وarguments: شغّل إحدى دوال صفحتك)؛ notice (code: too_fast أو limit للكلمات المكتوبة)؛ ended (مع reason، ثم يُغلق المقبس) |
يُلقي الوكيل التحية فور اتصالك. ويمكن إضافة user_id وpage_tools (دوال الصفحة التي يرد عليها تطبيقك، انظر أدناه) إلى الطلب. تُفوتَر المكالمات بالدقيقة كأي مكالمة أخرى، بسجلات المكالمات والتحليل وWebhooks نفسها.
في مكالمة الويب (الودجت أو الصفحة المستضافة أو تطبيقك) يرى المتصل محادثة نصية بجوار الصوت، فيستطيع الوكيل أن يفعل أكثر من الكلام. أما المتصلون عبر الهاتف فلا يحصلون على شيء من ذلك.
فعّل الوكيل ← الأدوات ← الإرسال إلى المتصل (send_to_caller في واجهة الوكيل) فيستطيع الوكيل وضع حتى خمس بطاقات في آن واحد على شاشة المتصل: عنوان وسطر تحته ووصف وصورة ورابط وحتى زرَّي رد في كل بطاقة؛ ويمكنه أيضًا عرض حتى ثلاثة ردود سريعة تحت سؤال. لا تُقرأ الروابط بصوت عالٍ أبدًا.
لا يجوز للوكيل إرسال سوى الروابط والصور التي مُنحت له في تلك المكالمة: تعليماته وتحيته، وقاعدة المعرفة (المستند المقروء من صفحة ويب يحمل عنوانها)، وإجابات دوالك، والبطاقات الجاهزة. ويجب أيضًا أن يكون الرابط ضمن أحد allowed_hosts (وموقع البطاقة الجاهزة نفسه مسموح دائمًا). لا تُرسل الروابط التي يخترعها الوكيل أو التي يقرؤها المتصل بصوت عالٍ. والروابط إلى تلك المواقع في كلام الوكيل قابلة للنقر في المحادثة.
"send_to_caller": {
"enabled": true,
"allowed_hosts": ["shop.example.com", "*.cdn.example.com"],
"presets": [
{ "name": "hours", "when": "asked when we open", "title": "Opening hours",
"description": "Mon–Sat 9:00–18:00", "url": "https://shop.example.com/stores", "image_url": "" }
]
}
يصلك كل إرسال بصفته Webhook باسم call.message_sent (channel وitems مع title وurl، وquickReplies وblocked). تُرسل المكالمة 10 مرات كحد أقصى.
أثناء المكالمة يستطيع المتصل أيضًا أن يكتب (عنوان بريد إلكتروني أو رقم طلب) أو أن ينقر زر رد؛ فيجيب الوكيل عن ذلك كما يجيب عن الكلام، ويتوقف أولًا إن كان يتحدث. حتى 500 حرف في الرسالة، ورسالة واحدة في الثانية، و100 في المكالمة. وفي سجل المكالمة تُوسَم هذه الأدوار بأنها مكتوبة أو منقورة.
يمنح الودجت صفحتك كائنًا اسمه evasay. كل شيء اختياري، ولا يستمع إطار المكالمة إلى صفحتك إلا إذا كانت من المواقع المسموح بها للودجت (الوكيل ← النشر):
<script src="https://evasay.com/voice-widget.js" data-agent="AGENT_SLUG" async></script>
<script>
window.evasay = window.evasay || [];
evasay.push(function (agent) {
agent.setVariables({ plan: 'pro', page: location.pathname }); // for the next call
agent.update('Cart: 2 items, $120', { key: 'cart' }); // during it
agent.registerTool('add_to_cart', async function (args) {
// your code, in the visitor's browser
return { ok: true, checkout: 'https://shop.example.com/checkout' };
});
agent.on('cards', function (cards) {}); // also 'live', 'ended'
});
</script>
setVariables العنصر {{name}} في التعليمات والتحية. وهي تأتي من متصفح الزائر، لذا يُخبَر الوكيل بأنها غير موثَّقة، ولا تصل أبدًا إلى دوالك أو إلى استعلام البدء.update الوكيل بما يحدث في الصفحة دون أن يجعله يرد؛ والتحديث الأحدث بالمفتاح key نفسه يحل محل الأقدم."kind": "page"، بلا url) وسجّل في صفحتك دالة بالاسم نفسه. لا يستطيع الوكيل استدعاءها إلا في مكالمات من صفحة سجّلتها؛ وينتظر الإجابة حتى timeout_sec (من 1 إلى 10، الافتراضي 5) ما لم تكن قيمة wait_for_result هي false. وتعمل بجلسة الزائر المسجَّل دخوله، كأنها نقرة منه: اطلب التأكيد في صفحتك قبل أي شيء يكلّف مالًا أو لا يمكن التراجع عنه. ويمكن إرسال الروابط في إجابتها كبطاقات.اضبط من يمكنه بدء مكالمة على بالرمز المميز فقط، واجعل خادمك يحصل على رمز لمرة واحدة للمستخدم المسجَّل دخوله:
curl https://evasay.com/api/v1/voice/web-calls \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "agent_id": "AGENT_ID", "user_id": "u_42", "variables": { "name": "Ann" }, "expires_in": 600 }'
يحتوي الرد على token (مكالمة واحدة، خلال expires_in ثانية، من 30 إلى 3600، الافتراضي 600) وagent (المعرّف النصي slug) وweb_call_url. سلّم الرمز إلى الصفحة عبر data-token-url="/your/endpoint" على سكربت الودجت (يرسل POST إلى هناك مع كوكيز الزائر ويقرأ { "token": "…" }) أو عبر agent.setToken(async () => token). وقيم variables في الرمز موثَّقة: يجوز أن تستخدمها التعليمات واستعلام البدء وقوالب دوالك، وكذلك user_id الذي تحتفظ به المكالمة (userId في المكالمة، وuser_id لتصفية المكالمات). أبقِ مفتاح API على خادمك.
في تطبيقك الخاص، أرسل POST بالمحتوى { "token": "…", "pageTools": ["add_to_cart"] } إلى https://evasay.com + web_call_url. الرد هو اتصال المكالمة (عنوان عرض WebRTC أو عنوان WebSocket، مع رمز المكالمة) لعميل RTVI مثل حزم تطوير العميل (SDK) من Pipecat للويب وiOS وAndroid وReact Native. تصل البطاقات ودوال الصفحة والتنبيهات كرسائل RTVI من نوع server-message (evasay.cards وevasay.tool وevasay.notice)؛ أرسل الكلمات المكتوبة عبر send-text وبلاغات الصفحة وإجاباتها كرسائل client-message من نوع evasay.context وevasay.tool_result. أو انقل الصوت بنفسك عبر الصوت عبر WebSocket مع تمرير user_id وpage_tools.
من أرقام الهاتف ← SIP يمكن لمقسّمك الخاص (PBX) أو هواتف SIP أو خط SIP trunk الخاص بك أن يتصل بوكلائك مباشرة؛ ويفوتر مزوّد SIP لديك المكالمات:
sip:ev…@<EvaSay's SIP domain>، للمكالمات الواردة فقط، للمقسّمات (3CX وFreePBX وAsterisk…) وهواتف SIP.from)؛ وتُسلَّم التحويلات إلى شخص إلى الخط عبر REFER. وعندما يطلب الخط بيانات اعتماد، تردّ EvaSay باسم مستخدم الخط وكلمة مروره اللذين أدخلتهما.تسجّل المكالمات الواردة الدخول بطريقة digest باسم المستخدم وكلمة المرور اللذين تمنحك إياهما EvaSay (الـrealm هو نطاق SIP)؛ ويمكنك أيضًا تقييد عناوين IP المصدر، أو القبول بعنوان IP وحده عندما لا يستطيع مزوّدك تسجيل الدخول (وتصبح عناوين IP حينئذ إلزامية). لكل عنوان SIP أو خط حدّ للمكالمات المتزامنة؛ وما يتجاوزه تتلقى مكالماته الرد 486. تُعرض كلمات المرور مرة واحدة، عند إنشائها أو إعادة تعيينها. UDP وG.711 (PCMU وPCMA) فقط؛ والمفاتيح عبر RFC 4733 أو SIP INFO؛ أوقف التسجيل (REGISTER) على خط مقسّمك.
تتصل الحملة بقائمة جهات اتصال عبر وكيل واحد، ضمن ساعات الاتصال وحدّ التزامن (max_concurrency، حتى 100 مكالمة في وقت واحد، ولا يزيد أبدًا عن حدّ المكالمات المتزامنة في مساحة عملك)، وتعيد المحاولة مع من لم تستطع الوصول إليهم.
curl https://evasay.com/api/v1/voice/campaigns \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Appointment reminders",
"agent_id": "AGENT_ID",
"phone_number_id": "PHONE_NUMBER_ID",
"timezone": "America/New_York",
"window_start": "09:00",
"window_end": "18:00",
"max_concurrency": 2,
"max_attempts": 2,
"retry_delay_min": 60,
"consent_confirmed": true,
"contacts": [
{ "phone": "+14155550100", "name": "Alex", "appointment": "Tuesday 3 pm" }
]
}'
يمكن أن تكون جهات الاتصال أيضًا نص CSV يكون رقم الهاتف في عموده الأول. الحقل consent_confirmed: true مطلوب: به تؤكد أن كل من في القائمة وافق على الاتصال به، بما في ذلك عبر صوت ذكاء اصطناعي، وتحتفظ EvaSay بهذا التأكيد مع الحملة (consent_confirmed_at). تُنشأ الحملة كمسوّدة؛ ابدأها عبر POST /api/v1/voice/campaigns/{id}/start، واستخدم pause أو cancel بالطريقة نفسها. يجب أن يكون الوكيل منشورًا قبل بدء الحملة.
مع تفعيل voicemail_detection (الافتراضي) تنتظر المكالمة الصادرة أن يتكلم الطرف الآخر قبل أن يُلقي الوكيل التحية؛ وإن ظلّوا صامتين ألقى الوكيل التحية بعد ثانيتين أو ثلاث. وعندما يسمع الوكيل بريدًا صوتيًا أو تسجيلًا من شركة الاتصالات ينتظر حتى تنتهي التحية وصافرتها، ثم يترك voicemail_message، أو يُغلق الخط إن لم توجد رسالة. تنتهي هذه المكالمات بقيمة ended_reason هي voicemail، وتُفوتَر عن المدة التي استغرقتها، ولا تُحلَّل ولا يُبلَّغ عنها.
في الحملة يُعاد الاتصال برقم وصل إلى بريد صوتي كما يُعاد برقم لم يردّ، ولا تُترك الرسالة إلا في المحاولة الأخيرة، حتى لا يتلقى أحد الرسالة نفسها مرتين.
تفحص كل مكالمة صادرة، من حملة أو من POST /api/v1/voice/calls، قائمة عدم الاتصال في مساحة العمل أولًا. الرقم المدرج فيها لا يُطلَب أبدًا: تردّ الواجهة بـ409 مع code هو do_not_call، وتوسم الحملة جهة الاتصال بـcanceled مع outcome هو do_not_call وتنتقل إلى التالية.
عندما يطلب الشخص في مكالمة أجراها الوكيل ألّا يُتصل به مجددًا، يُدرج الوكيل رقمه في القائمة بنفسه، ويخبره بذلك، ويُرسَل الـWebhook باسم call.do_not_call. ويمكن أيضًا إضافة الأرقام وإزالتها من الحملات ← قائمة عدم الاتصال أو عبر الواجهة البرمجية:
curl https://evasay.com/api/v1/voice/do-not-call \
-X POST \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{ "phones": ["+14155550100"], "note": "Asked by email" }'
الأرقام بالصيغة الدولية؛ وحتى 1000 رقم في المرة الواحدة. يعرضها GET /api/v1/voice/do-not-call الأحدث أولًا (search وlimit وpage)، ولكل رقم قيمة source (call أو dashboard أو api). ويُزيل DELETE /api/v1/voice/do-not-call/%2B14155550100 رقمًا من القائمة؛ لا تفعل ذلك إلا بعد أن يوافق الشخص على أن يُتصل به.
ينشئ POST /api/v1/voice/voices صوتًا من تسجيل WAV لمتحدث واحد (multipart بالحقول audio وname وlanguage وconsent=true). يردّ بـ202 وبالحالة running؛ استعلم عبر GET /api/v1/voice/voices إلى أن تصبح ready، ثم اضبط voice_id للوكيل على voice_id الصوت. language هي اللغة المنطوقة في التسجيل، أي لغة من لغات الوكلاء المذكورة أعلاه؛ يتحدث الصوت جميعها عدا الصينية، إذ يرد صوت مدمج من الجنس نفسه، ويشبه المتحدث في التسجيل أكثر ما يشبهه بلغة التسجيل. كل صوت مستنسخ يكلّف رصيدًا، تعرضه لوحة التحكم قبل أن تنشئ واحدًا.
أضف عنوان https من التكاملات ← Webhooks والإشعارات لتلقّي أحداث المكالمات:
| الحدث | متى |
|---|---|
call.started | ردّ الوكيل |
call.ended | انتهت المكالمة، مع مدتها ورصيدها |
call.analyzed | جاهزية الملخص والنتيجة والحقول المستخرجة والنص المفرَّغ |
call.transcript | أثناء المكالمة، أسطر النص المفرَّغ الجديدة كل بضع ثوان |
call.tool_called | استدعى الوكيل إحدى دوالك: name وarguments وstatus وdurationMs |
call.handed_off | سُلِّمت المكالمة إلى وكيل آخر: fromAgentId وtoAgentId |
call.transferred | حُوِّلت المكالمة إلى شخص: destination |
call.voicemail | وصلت مكالمة صادرة إلى بريد صوتي |
call.do_not_call | طلب الشخص في مكالمة صادرة ألّا يُتصل به مجددًا: phone |
call.recording_ready | خُزِّن التسجيل ثنائي القناة: recordingUrl (صالح 24 ساعة) وdurationMs |
call.message_sent | عرض الوكيل بطاقات على شاشة متصل عبر الويب أو التطبيق: items وquickReplies |
alert.triggered | تجاوز أحد تنبيهاتك (Webhooks والإشعارات ← التنبيهات) عتبته |
alert.resolved | عاد ذلك التنبيه إلى الوضع الطبيعي |
تحمل الأحداث المرسلة أثناء المكالمة data.call (id وagentId وchannel وdirection والأرقام). وكل طلب موقَّع:
EvaSay-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
EvaSay-Delivery: <delivery id>
تحقق من التوقيع بسرّ الـWebhook الذي عُرض عند إنشائه، وردّ بحالة 2xx. تُعاد محاولة عمليات التسليم الفاشلة بعد دقيقة و5 دقائق و30 دقيقة وساعتين و12 ساعة بالمحتوى نفسه ومعرّف EvaSay-Delivery نفسه، فيمكنك تجاهل التكرارات. وتُعرض آخر عمليات تسليم الـWebhook، بالمحتوى الذي أُرسل بالضبط وبالحالة التي ردّت بها نقطة نهايتك، عبر GET /webhooks/{id}/deliveries وفي لوحة التحكم؛ ويعيد POST /webhooks/{id}/deliveries/{delivery_id} إرسال إحداها.
وإلى جانب البريد الإلكتروني وWebhooks من نوع alert.triggered / alert.resolved، يمكن أن تذهب التنبيهات إلى قناة Slack (incoming webhook) أو روبوت مجموعة WeCom أو Telegram من Webhooks والإشعارات ← التنبيهات ← الإرسال أيضًا إلى.
للأخطاء شكل واحد:
{
"error": {
"type": "invalid_request_error",
"code": "invalid_agent_field",
"message": "status must be draft or published",
"param": "status"
}
}
| الحالة | المعنى |
|---|---|
| 400 | إدخال غير صالح (يحدد code وparam أيَّ حقل) |
| 401 | مفتاح API مفقود أو غير صالح |
| 402 | رصيد غير كافٍ لبدء المكالمة |
| 403 | المفتاح للقراءة فقط، أو الوكيل غير متاح |
| 404 | لا يوجد وكيل أو مكالمة أو حملة بهذا المعرّف في مساحة العمل هذه |
| 409 | حالة غير صحيحة (مثل بدء حملة قيد التشغيل)، أو حساب مزوّد غير متصل، أو الرقم في قائمة عدم الاتصال (do_not_call) |
| 429 | طلبات كثيرة جدًا؛ خفّف الوتيرة وأعد المحاولة |
تُعرض طلبات واجهة الصوت البرمجية لمساحة العمل خلال آخر 30 يومًا (الوقت ونقطة النهاية والحالة والمدة والمفتاح ورمز الخطأ؛ دون المحتوى) ضمن مفاتيح API ← سجل طلبات API.
القراءات محدودة بـ120 طلبًا في الدقيقة لكل مفتاح، والكتابات والمكالمات بـ30.
تُفوتَر المكالمات بالدقيقة من رصيد مساحة العمل، وهو الرصيد نفسه الذي تستخدمه لوحة التحكم. الأسعار الحالية في صفحة الأسعار.
استخدم عقد OpenAPI لتوليد عميل للتكامل. تعمل الواجهة البرمجية العامة ولوحة التحكم ونقطة نهاية إدارة MCP على موارد مساحة العمل وصلاحياتها نفسها.
| القدرة | نقطة النهاية |
|---|---|
| أدوات قابلة لإعادة الاستخدام | GET / POST /api/v1/voice/tools |
| قراءة أداة / تحديثها / حذفها | GET / PATCH / DELETE /api/v1/voice/tools/{id} |
| معاينة أداة أو اختبارها | POST /api/v1/voice/tools/{id}/test |
| ربط الأدوات بوكيل | PUT /api/v1/voice/agents/{id}/tools |
| قواعد المعرفة | GET / POST /api/v1/voice/knowledge-bases |
| قراءة قاعدة معرفة / تحديثها / حذفها | GET / PATCH / DELETE /api/v1/voice/knowledge-bases/{id} |
| إضافة المستندات / عرضها | POST / GET /api/v1/voice/knowledge-bases/{id}/documents |
| قراءة مستند / حذفه | GET / DELETE /api/v1/voice/knowledge-bases/{id}/documents/{doc_id} |
| الاشتراكات في أحداث المكالمات | GET / POST /api/v1/voice/webhooks |
| قراءة اشتراك / تحديثه / حذفه | GET / PATCH / DELETE /api/v1/voice/webhooks/{id} |
| إرسال حدث اختبار موقَّع | POST /api/v1/voice/webhooks/{id}/test |
| اكتشاف أدوات MCP البعيدة | POST /api/v1/voice/mcp/discover |
| نقطة نهاية إدارة MCP | /api/v1/voice/mcp |
سجّل أداة HTTP تستعلم عن مهايئ CRM لديك:
{
"name": "lookup_customer",
"description": "Find a customer after confirming their customer ID.",
"kind": "http",
"url": "https://crm.example.com/customers/{{customer_id}}",
"method": "GET",
"read_only": true,
"credential_ref": "crm",
"input_schema": {
"type": "object",
"properties": { "customer_id": { "type": "string" } },
"required": ["customer_id"],
"additionalProperties": false
},
"response_path": "data"
}
يُرجع POST /tools القيمة { "data": { "id": "TOOL_ID", ... } }. اربط تعريفها بوكيل عبر PUT /agents/AGENT_ID/tools مع { "tool_ids": ["TOOL_ID"] }. يستبدل هذا قائمة الأدوات كلها بلقطات؛ فأعد الربط عندما تتغير أداة في المكتبة. وحذف تعريف من المكتبة يُبقي اللقطات الموجودة. ويمكنك أيضًا قراءة التعريفات المضمَّنة واستبدالها عبر الحقل tools في واجهة الوكيل. استخدم analysis_config وwidget_config لضبط التحليل والودجت عبر واجهة الوكيل.
يمكن للأداة استخدام GET أو POST أو PUT أو PATCH أو DELETE. يقبل query وrequest_body قوالب JSON متداخلة مثل { "customer": { "id": "{{customer_id}}" } }. العنصر النائب الكامل يحافظ على نوع JSON الأصلي. تُرمَّز العناصر النائبة في عنوان URL ولا يجوز أن تظهر إلا بعد مضيف HTTPS عام ثابت. وبدون request_body تتلقى الأدوات غير GET القيمة { "arguments": {...}, "call": { "callId": "...", "agentId": "...", "toolCallId": "...", "idempotencyKey": "..." } }. يختار response_path حقلًا بصيغة النقاط. ما زالت parameters البسيطة مقبولة؛ ويدعم input_schema كذلك الكائنات المتداخلة والمصفوفات والتعدادات والحدود الرقمية. لا تُقبل مراجع المخططات الخارجية ولا التعبيرات النمطية.
static_args: قيم تُرسل مع كل استدعاء مهما كتب النموذج، مثل معرّف متجر؛ وتملأ أيضًا {{name}} في العنوان والمحتوى.extract: يحتفظ [{name, path}] بحقول من إجابة دالة (data.id) لتُستخدم في {{name}} للدوال اللاحقة، فيمكن لـcustomer_id من استعلام أن يدخل في الطلب التالي دون أن يكرّره النموذج. وتُحفظ حقول استعلام البدء بالطريقة نفسها.reject_when: حتى 5 قواعد {on: caller|agent, pattern, negate}؛ ما دامت كلها متحققة على آخر الكلمات، لا تُشغَّل الدالة ويتلقى الوكيل reject_message.model_says: في كل استدعاء يكتب النموذج جملة واحدة تُقال أثناء تشغيل الدالة، بدل speak_before الثابتة.اربط تطبيقًا من التكاملات ← Webhooks والإشعارات ← التطبيقات المتصلة، ثم استخدم «إضافة دالة جاهزة» في تبويب المعرفة والأدوات للوكيل؛ ولا تحتاج إلى نقطة نهاية خاصة بك:
check_availability (الأوقات الفارغة في تاريخ ما) وbook_appointment (يحجز الوقت الذي اختاره المتصل). تتبع أوقات Google Calendar المنطقة الزمنية وأيام الدوام والساعات ومدة الموعد التي تضبطها؛ ويستخدم Cal.com توافر نوع الحدث نفسه، وبريدًا إلكترونيًا احتياطيًا تضبطه لحالة ألّا يعطي المتصل بريدًا.save_to_sheet، وهي تُلحق صفًّا بالأعمدة التي تذكرها، إضافةً إلى معرّف المكالمة ووقتها.notify_team، وهي تنشر في قناة Slack (incoming webhook) رسالة يكتبها الوكيل.يشغّل مستوى التحكم في EvaSay هذه الدوال بالحساب الذي ربطته؛ فلا يحتفظ الـworker ولا تعريف الوكيل ببيانات اعتماد التطبيق. وعند قراءة وكيل عبر الواجهة البرمجية تظهر بصيغة kind: "app" (مع app وaction وconnection_id وapp_config)؛ أعِدها كما هي عند استبدال tools لتبقى. تُربَط التطبيقات من لوحة التحكم فقط.
اضبط run_at_start: true على إحدى أدوات الوكيل فتُستدعى عند بدء كل مكالمة، قبل أن يُلقي الوكيل التحية أو يرد. تُملأ له المعاملات المسمّاة caller_number وcalled_number وdirection وchannel وcall_id. وتملأ الحقول التي تُرجعها {{variables}} في first_message وsystem_prompt وidle_messages (والحقول المتداخلة بمستوى واحد مثل {{customer.name}})، وتُعطى الإجابة كلها للوكيل كخلفية. تنتظر التحية التي تحوي متغيرات الإجابة حتى 3 ثوان؛ وما لا يُعثر عليه يُترك فارغًا. يمكن لأداة واحدة لكل وكيل أن تعمل عند البدء.
تُضبط بيانات الاعتماد في بيئة الخادم لمساحة عملك ووجهتك؛ اطلب من support@evasay.com تهيئة credential_ref. لا تضع مفاتيح API في تعريفات الوكلاء أو الترويسات أو التعليمات أو معاملات الأدوات. يمكن لمهايئك أن يحتفظ ببيانات اعتماد CRM في بيئته الخاصة.
عاين أداة قبل إرسال الطلبات إلى نظام الأعمال:
{
"arguments": { "customer_id": "customer-123" },
"dry_run": true,
"mock_result": { "name": "Alex", "order_status": "shipped" }
}
تتحقق المعاينة من المعاملات وتعرض الطلب الناتج؛ ولا تُجري محادثة ولا تتصل بنظام الأعمال. اضبط dry_run=false للتنفيذ الفعلي. ويتطلب اختبار الكتابة الحي أيضًا confirmed=true وidempotency_key (من 8 إلى 128 حرفًا أو رقمًا أو نقطة أو شرطة سفلية أو نقطتين رأسيتين أو شرطة). تتضمن ردود الاختبار ok وstatus وduration_ms ونتيجة محدودة الحجم. ولا تُرجع بيانات اعتماد. تتطلب اختبارات القراءة والكتابة صلاحية الكتابة في مساحة العمل.
أثناء المكالمة تحمل طلبات الأعمال Idempotency-Key ثابتًا. يجب أن تحترمه نقطة نهاية الأعمال لديك. تُزال تكرارات عمليات الكتابة المتطابقة داخل المكالمة، بما في ذلك العمليات المجهولة النتيجة بعد انتهاء المهلة. أما العملية المختلفة المقصودة فتحتاج إلى معامل أعمال مميّز، مثل operation_id. لا تعيد EvaSay تشغيل عمليات الكتابة تلقائيًا. تتضمن أحداث تنفيذ الأدوات الحالة والمدة؛ وتبقى ميزة اختبار المحادثة محاكاة نصية، لا اختبارًا لتنفيذ الأدوات.
اضبط اتصال MCP من نوع Streamable HTTP بما يلي:
URL: https://evasay.com/api/v1/voice/mcp
Authorization: Bearer <your EvaSay API key>
في Claude Code مثلًا:
claude mcp add --transport http evasay https://evasay.com/api/v1/voice/mcp --header "Authorization: Bearer $EVASAY_API_KEY"
يخبر الاتصال الأداة بكيفية بناء وكيل: قراءة الكتالوج، وإنشاء مسودة، وإضافة المعرفة والدوال وقوائم الكلمات، وكتابة الاختبارات وتشغيلها، وتصحيح المسودة حتى تنجح، وإعطاؤك dashboard_url الخاص بالوكيل لتجربته، ثم النشر وتوجيه رقم فقط بعد موافقتك. يمكن للأدوات التي تقرأ الوثائق أن تبدأ من https://evasay.com/llms.txt، الذي يربط بهذه الصفحة وبعقد OpenAPI وبعنوان MCP.
استخدم إعداد الرمز المميز الآمن أو متغيرات البيئة في العميل. تستخدم نقطة النهاية مصادقة مفتاح API، لا مسار تسجيل دخول OAuth. وهي تتيح إنشاء الوكلاء وضبطهم وأدوات المكتبة والمعرفة وWebhooks وسجلات المكالمات. النشر وإجراء المكالمات الفعلية إجراءات كتابة؛ والمكالمات الصادرة تستهلك رصيدًا ورسوم المشغّل. يعيد كل استدعاء أداة فحص صلاحيات مساحة العمل. فعّل ضوابط التأكيد في عميلك لإجراءات الكتابة. تستخدم نقطة النهاية ردود JSON عديمة الحالة؛ ولا تقدّم تدفق إشعارات في الخلفية.
مثال على تعليمة لأداة البرمجة: «أنشئ وكيل EvaSay كمسوّدة، وسجّل نقطة نهاية البحث في CRM الخاص بي، وعايِنها بمعاملات اختبار، واربطها بالوكيل، واضبط Webhook من نوع call.analyzed». راجع النشر والمكالمات الفعلية وأذن بها صراحةً.
يقبل POST /mcp/discover القيمة { "url": "https://crm.example.com/mcp", "credential_ref": "crm" } ويُرجع أدوات الخادم ومخططاته. سجّل الأداة المحددة فقط:
{
"name": "lookup_customer",
"description": "Find a CRM customer by confirmed ID.",
"kind": "mcp",
"url": "https://crm.example.com/mcp",
"mcp_tool": "get_customer",
"credential_ref": "crm",
"read_only": true,
"input_schema": {
"type": "object",
"properties": { "customer_id": { "type": "string" } },
"required": ["customer_id"]
}
}
لا تتاح للوكيل إلا الأدوات المسجَّلة. تدعم الاتصالات البعيدة Streamable HTTP مع ردود JSON أو SSE على الطلبات، ووجهات HTTPS العامة، وبيانات الاعتماد المهيَّأة مسبقًا. لا تُدعم نقاط نهاية SSE القديمة، ولا التفاوض عبر OAuth، ولا sampling/elicitation التي يبدؤها الخادم، ولا المرفقات الثنائية. ولا يمنح الاكتشاف تلقائيًا إمكانية الوصول إلى كل أدوات الخادم. ويجب أن يكون مخطط الأداة البعيدة مضمَّنًا ويستخدم المجموعة الفرعية المدعومة من JSON Schema.
أنشئ Webhook عبر POST /webhooks مع { "url": "https://crm.example.com/evasay-events", "events": ["call.analyzed"] }. يحتوي الرد على الاشتراك وسرّ توقيع مولَّد، لا يُعاد إلا عند الإنشاء. تحقق من EvaSay-Signature، وأزل تكرار EvaSay-Delivery، وحدّث CRM لديك. إن Webhooks الأحداث إشعارات غير متزامنة؛ أما الأدوات أثناء المكالمة فتُرجع نتائجها مباشرة إلى الوكيل.