API و MCP برای مرکز تلفن اختصاصی شما
مرکز تلفن اختصاصی Cenaly برای برنامهها و دستیارهای هوش مصنوعی شما باز است:
- CRM، سیستم حسابداری، وبسایت شما — REST API: گزارش تماسها، ضبط و پیادهسازی گفتار، تماس با یک کلیک، داخلیها، انتقال تماس، قواعد تماس؛
- Claude Code، Claude Desktop، Cursor — سرور MCP راه دور با کلید؛
- ChatGPT، claude.ai، Perplexity، Cursor و VS Code — همان سرور MCP بدون کلید: وارد حساب خود میشوید و دسترسی را مجاز میکنید (OAuth).
همهچیز به نام مالک حساب و فقط با مجوزهایی کار میکند که او اعطا کرده است. هر تغییر در گزارش اقدامات مرکز تلفن با نام کلید یا برنامه قابل مشاهده است.
آدرسها#
| مورد | آدرس |
|---|---|
| REST API | https://api.cenaly.com/pbx-api/v1 |
| سرور MCP (streamable HTTP) | https://api.cenaly.com/pbx-api/mcp |
| مستندات متدها | api.cenaly.com/pbx-api/v1/docs |
| توصیف OpenAPI 3.1 | api.cenaly.com/pbx-api/v1/openapi.json |
| فراداده OAuth | https://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api |
کلید و مجوزها#
کلید را فقط مالک حساب ایجاد میکند: تلفنی → API و MCP → کلیدها → ایجاد کلید. کارمندی با نقش «مدیر مرکز تلفن» کلیدها را نمیبیند — کلید به نام مالک عمل میکند.
- کلید با قالب
cpx_…فقط یک بار نمایش داده میشود — بلافاصله پس از ایجاد، همراه با قطعهکدهای آماده برای اتصال. نزد ما فقط اثر انگشت آن (SHA-256) نگهداری میشود؛ بازیابی کلید ممکن نیست — فقط میتوان کلید جدید صادر کرد. - کلید را میتوان به شعبهها محدود کرد (در غیر این صورت — همه شعبهها، از جمله شعبههای آینده) و به مدت (۳۰، ۹۰، ۳۶۵ روز یا بدون انقضا).
- «مجوزها» مجوزها و شعبههای کلید را در لحظه تغییر میدهند: یکپارچهسازی به کار خود ادامه میدهد و مجوزهای جدید از درخواست بعدی اعمال میشوند.
- «لغو» — فوری و برای همیشه: درخواست بعدی با این کلید 401 دریافت میکند.
- کلیدها و اتصالهای فعال — حداکثر ۲۰ در هر حساب.
مجوزها با مجموعههای آماده یا با تیک انتخاب میشوند:
| مجوز | چه میدهد | مجموعهها |
|---|---|---|
calls:read |
گزارش تماسها و کارت تماس با مسیر | CRM، دستیار هوش مصنوعی، فقط خواندن، همه |
recordings:read |
پیوند به ضبط گفتگو (۱۰ دقیقه) و پیادهسازی گفتار | CRM، دستیار هوش مصنوعی، فقط خواندن، همه |
calls:dial |
تماس با یک کلیک: ابتدا تلفن کارمند زنگ میخورد، پس از پاسخ مرکز تلفن شماره را میگیرد | CRM، دستیار هوش مصنوعی، همه |
extensions:read |
داخلیها، گروهها، انتقال تماس، «مزاحم نشوید» | CRM، دستیار هوش مصنوعی، فقط خواندن، همه |
extensions:write |
تغییر انتقال تماس شخصی و «مزاحم نشوید» | دستیار هوش مصنوعی، همه |
presence:read |
چه کسی آزاد است، در حال تماس است، در حال گفتگو است | دستیار هوش مصنوعی، فقط خواندن، همه |
reports:read |
شاخصهای مرکز تماس در یک دوره: سطح خدمات، انتظار، تماسهای رهاشده، AHT، FCR، CSAT، کجا تماسها را از دست میدهیم، تفکیک بر اساس صفها، خطوط، کارمندان | فقط خواندن، همه |
routes:read |
شمارهها، قواعد تماسهای ورودی و خروجی، تاریخچه قواعد | فقط خواندن، همه |
routes:write |
ایجاد، تغییر، حذف و جابهجایی قواعد تماس، بازگردانی از تاریخچه | فقط با تیک جداگانه |
config:export |
خروجی تنظیمات مرکز تلفن در قالب فایل | فقط با تیک جداگانه |
config:import |
بارگذاری تنظیمات از جدولها: پیشنمایش، سپس اعمال | فقط با تیک جداگانه |
webhooks:write |
ایجاد، تغییر، بررسی و حذف وبهوکهای رویدادهای تماس | فقط با تیک جداگانه |
daynight:write |
بستن شعبه تا پایان شبانهروز یا تا یک تاریخ، باز کردن — همان *28 از تلفن |
فقط با تیک جداگانه |
مجوزهایی که چیزی را تغییر میدهند یا دقیقه مصرف میکنند، در پنجره با رنگ کهربایی مشخص شدهاند. سه مجوز آخر در هیچ مجموعهای، حتی در «همه»، قرار ندارند — آنها را فقط میتوان آگاهانه و با تیک جداگانه اعطا کرد.
ChatGPT، claude.ai، Perplexity، Cursor، VS Code: اتصال بدون کلید#
دستیارهای ابری نمیتوانند کلید را در سرصفحه قرار دهند — آنها سرور MCP را از طریق OAuth متصل میکنند. نیازی به ایجاد کلید نیست.
claude.ai: تنظیمات → اتصالدهندهها → افزودن اتصالدهنده خود → https://api.cenaly.com/pbx-api/mcp را وارد کنید → اتصال.
ChatGPT: تنظیمات → برنامهها و اتصالدهندهها → پیشرفته → حالت توسعهدهنده را فعال کنید → ایجاد → https://api.cenaly.com/pbx-api/mcp را وارد کنید، احراز هویت — OAuth.
Perplexity: تنظیمات حساب → اتصالدهندهها → «+ اتصالدهنده خود» → راه دور → https://api.cenaly.com/pbx-api/mcp را وارد کنید، احراز هویت — OAuth.
Cursor و VS Code: سرور MCP راه دور (HTTP) را با آدرس https://api.cenaly.com/pbx-api/mcp و بدون سرصفحه کلید اضافه کنید — پنجره ورود در مرورگر باز میشود. در Cursor: .cursor/mcp.json → {"mcpServers": {"cenaly-pbx": {"url": "https://api.cenaly.com/pbx-api/mcp"}}}؛ در VS Code: فرمان «MCP: Add Server» → HTTP.
سپس دستیار پنجره ورود Cenaly را باز میکند. پس از ورود خواهید دید:
- چه کسی درخواست دسترسی میکند — برنامه با آدرسی که پاسخ به آن بازمیگردد نامگذاری میشود: «اتصالدهنده تأییدشده · chatgpt.com» (به همین ترتیب — claude.ai، perplexity.ai، vscode.dev، Cursor)، «برنامه روی این رایانه» یا هشدار «آدرس ناشناس». نامی که برنامه فرستاده، ریز نمایش داده میشود — هر کسی میتواند آن را بنویسد؛
- مجوزها — آنچه برنامه درخواست میکند علامتگذاری شده است (اگر «همهچیز» را درخواست کند، مجموعه «دستیار هوش مصنوعی» علامتگذاری میشود)؛ مجوزهای «فقط با تیک جداگانه» هرگز از پیش علامتگذاری نمیشوند؛
- شعبهها — همه یا انتخابشدهها.
«مجاز کردن» شما را به دستیار بازمیگرداند و او بلافاصله ابزارهای مرکز تلفن را میبیند. اتصال در تلفنی → API و MCP → کلیدها با برچسب OAuth و آدرس برنامه ظاهر میشود — همانجا مجوزها تغییر میکنند و دسترسی لغو میشود. اتصال مجدد همان برنامه مجوزهای آن را بهروزرسانی میکند، نه اینکه اتصال دومی ایجاد کند.
فقط مالک حساب میتواند اتصالها را مجاز کند.
Claude Code، Claude Desktop، Cursor: اتصال با کلید#
Claude Code — با یک فرمان:
claude mcp add --transport http telephony https://api.cenaly.com/pbx-api/mcp --header "Authorization: Bearer cpx_…"
Claude Desktop، Cursor (.cursor/mcp.json) و سایر کلاینتها با فایل تنظیمات:
{
"mcpServers": {
"telephony": {
"type": "http",
"url": "https://api.cenaly.com/pbx-api/mcp",
"headers": { "Authorization": "Bearer cpx_…" }
}
}
}
قطعههای آماده با کلید شما بلافاصله پس از ساخت کلید نمایش داده میشوند. دستیار هوش مصنوعی فقط ابزارهایی را میبیند که کلید مجاز کرده است و میتواند به «چه کسی امروز زنگ زد و تماس برقرار نشد»، «با تلفن آنا به این مهمان پستماس بگیر»، «برای من انتقال تماس به موبایل را روشن کن» پاسخ دهد.
REST API#
کلید — در سرآیند Authorization: Bearer <ключ> (یا X-Api-Key). اگر کلید یک شعبه داشته باشد، میتوان پارامتر location را نفرستاد؛ اگر چند شعبه داشته باشد، پاسخ 400 location_required آنها را فهرست میکند.
| روش | مسیر | دسترسی | کارکرد |
|---|---|---|---|
| GET | /v1/me |
— | دسترسیها، شعبهها و محدودیتهای کلید |
| GET | /v1/locations |
— | شعبههای کلید و مرکز تلفن آنها |
| GET | /v1/calls |
calls:read |
دفترچه تماسها: since، until، direction، status (answered، missed، ai)، number، extension، limit تا 100، cursor |
| GET | /v1/calls/{id} |
calls:read |
تماس با مسیر: کدام قاعده اجرا شد، تلفن چه کسی زنگ خورد، چه کسی پاسخ داد |
| GET | /v1/calls/{id}/recording |
recordings:read |
پیوند ضبط به مدت 10 دقیقه |
| GET | /v1/calls/{id}/transcript |
recordings:read |
پیادهسازی متن و خلاصه گفتگو |
| POST | /v1/dial |
calls:dial |
تماس با یک کلیک: { "extension": "101", "number": "+995555123456" } |
| GET | /v1/dial/{commandId} |
calls:dial |
وضعیت تماس با یک کلیک |
| GET | /v1/extensions |
extensions:read |
داخلیها، گروهها، انتقال تماس، «مزاحم نشوید» |
| PUT | /v1/extensions/{ext}/forwarding |
extensions:write |
انتقال تماس شخصی داخلی |
| PUT | /v1/extensions/{ext}/dnd |
extensions:write |
«مزاحم نشوید»: { "on": true } |
| GET | /v1/presence |
presence:read |
چه کسی همین حالا آزاد است |
| GET | /v1/metrics |
reports:read |
شاخصهای مرکز تماس برای یک دوره: from، to (تاریخهای محلی شعبه YYYY-MM-DD، پیشفرض — 7 روز گذشته)، compare (prev، year، prev,year یا خالی)، sections (metrics,loss,queues,lines,operators,directions,heatmap,daily)، callbacks=true — و همچنین سرعت پستماس |
| GET | /v1/routes |
routes:read |
شمارهها، قواعد تماس ورودی و خروجی |
| GET | /v1/routes/history |
routes:read |
تاریخچه تغییرات قواعد |
| POST، PUT، DELETE | /v1/routes/inbound…، /v1/routes/outbound… |
routes:write |
قواعد تماس یکییکی: ساخت، تغییر فیلدهای ارسالی، حذف، جابهجایی، بازگردانی |
| GET، POST | /v1/config/export، /v1/config/import |
config:export، config:import |
تنظیمات در قالب فایل؛ بارگذاری — پیشنمایش، سپس اعمال |
| GET | /v1/events |
calls:read |
رویدادهای تماس شعبه در 7 روز (تا 2000): since (شناسه رویداد یا زمان)، types، limit (تا 500 در هر پاسخ) |
| GET، POST، PATCH، DELETE | /v1/webhooks… |
webhooks:write |
وبهوکها: فهرست، ساخت، تغییر، حذف؛ …/rotate-secret، …/test، …/deliveries |
| GET، PUT | /v1/open-closed |
routes:read، daynight:write |
بسته است یا نه و تا چه زمانی؛ بستن تا پایان شبانهروز { "closed": true }، تا تاریخ { "closed": true, "until": "2026-10-05T09:00" } یا باز کردن |
توضیح کامل فیلدها — در صفحه مستندات و در OpenAPI.
چه کسی امروز زنگ زد و تماس برقرار نشد:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/calls?status=missed&since=$(date -u +%Y-%m-%dT00:00:00Z)"
پستماس با مشتری از تلفن داخلی 101:
curl -X POST -H "Authorization: Bearer cpx_…" -H "Content-Type: application/json" \
-d '{"extension":"101","number":"+995555123456"}' "https://api.cenaly.com/pbx-api/v1/dial"
شاخصهای سپتامبر با مقایسه با اوت و سپتامبر سال گذشته — برای پنل BI خودتان:
curl -H "Authorization: Bearer cpx_…" \
"https://api.cenaly.com/pbx-api/v1/metrics?from=2026-09-01&to=2026-09-30&compare=prev,year"
در پاسخ metrics — همان اعدادی که در صفحه مخابرات → دفترچه تماسها → تحلیلات دیده میشود: تماسهای ورودی، پاسخدادهشده و ازدسترفته، سطح سرویس (آستانه و هدف — از تنظیمات صف)، میانگین و حداکثر انتظار، سهم رهاشدههای بدون تماس کوتاه، AHT، FCR، سهم انتقالها و ربات، CSAT. compare.prev و compare.year — همان فیلدها برای دوره گذشته و همان دوره یک سال پیش. مقایسه با سال گذشته برای دورههای تا 400 روز محاسبه میشود.
روشن کردن انتقال تماس به موبایل، اگر کارمند در 15 ثانیه پاسخ نداد:
curl -X PUT -H "Authorization: Bearer cpx_…" -H "Content-Type: application/json" \
-d '{"forward":{"noAnswer":{"kind":"number","number":"+995599000111"},"noAnswerSec":15}}' \
"https://api.cenaly.com/pbx-api/v1/extensions/101/forwarding"
ابزارهای MCP#
همان عملیاتهایی که در REST وجود دارد. کلاینت فقط ابزارهایی را میبیند که با کلید یا اتصال مجاز شدهاند:
| ابزارها | دسترسی |
|---|---|
list_locations |
— |
list_calls, get_call |
calls:read |
get_call_recording, get_call_transcript |
recordings:read |
call_number, get_dial_status |
calls:dial |
list_extensions |
extensions:read |
set_forwarding, set_do_not_disturb |
extensions:write |
get_presence |
presence:read |
get_call_metrics |
reports:read |
list_routes, list_route_history |
routes:read |
save_inbound_rule, delete_inbound_rule, move_inbound_rule, save_outbound_rule, delete_outbound_rule, move_outbound_rule, set_outbound_calls, restore_route_version |
routes:write |
export_config |
config:export |
import_config |
config:import |
get_call_events |
calls:read |
list_webhooks, save_webhook, delete_webhook, rotate_webhook_secret, test_webhook, list_webhook_deliveries |
webhooks:write |
get_open_closed |
routes:read |
set_open_closed |
daynight:write |
سرور بدون نشست کار میکند (streamable HTTP، JSON-RPC 2.0): initialize، tools/list، tools/call.
OAuth برای توسعهدهندگان کانکتورهای خودشان#
سرور مجوزدهی از مشخصات مجوزدهی MCP پیروی میکند — هر کلاینتی که از آن پشتیبانی کند مناسب است:
- درخواست به MCP بدون توکن، 401 با هدر
WWW-Authenticate: Bearer resource_metadata="https://api.cenaly.com/.well-known/oauth-protected-resource/pbx-api/mcp"دریافت میکند. - فرادادههای منبع (RFC 9728) سرور مجوزدهی را معرفی میکنند —
https://api.cenaly.com/pbx-api؛ فرادادههای آن (RFC 8414) در نشانیhttps://api.cenaly.com/.well-known/oauth-authorization-server/pbx-api(و…/pbx-api/.well-known/openid-configuration) قرار دارد. - ثبت پویا کلاینت (RFC 7591):
POST /pbx-api/oauth/register. نشانی بازگشت فقطlocalhost/127.0.0.1(هر پورتی) یا نشانی یک کانکتور شناختهشده است (claude.ai، claude.com، chatgpt.com، chat.openai.com، vscode.dev، www.perplexity.ai، enterprise.perplexity.ai؛ برای Cursor نیز دقیقاًcursor://anysphere.cursor-mcp/oauth/callback). روش ورود کلاینت —none(کلاینت عمومی)،client_secret_postیاclient_secret_basic. - کد مجوزدهی با PKCE (فقط
S256):GET /pbx-api/oauth/authorize→ پنجره ورود و رضایت مالک → بازگشت به نشانی شما باcode،stateوiss. پارامترresource— نشانی سرور MCP است. - توکنها:
POST /pbx-api/oauth/token. کد یکبارمصرف است و ۲ دقیقه اعتبار دارد (code_verifierنادرست آن را باطل میکند)؛ توکن دسترسی — ۱ ساعت؛ توکن تازهسازی — ۹۰ روز، با هر تازهسازی توکن جدید صادر میشود و توکن قبلی از کار میافتد. - لغو:
POST /pbx-api/oauth/revoke(RFC 7009) اتصال را بهطور کامل باطل میکند — مانند «لغو» در پنجره «API و MCP».
توکن دسترسی همهجا که کلید پذیرفته میشود پذیرفته میشود: هم در MCP و هم در REST، با همان دسترسیها و شعبههایی که مالک مجاز کرده است.
محدودیتها و خطاها#
- برای هر کلید یا اتصال: ۱۲۰ درخواست در دقیقه و ۲۰ ۰۰۰ در شبانهروز (REST و MCP با هم).
- تماس با یک کلیک — جداگانه: ۱۰ در دقیقه و ۳۰۰ در شبانهروز.
- ژورنال — تا ۱۰۰ تماس در هر درخواست؛ در ژورنال مرکز تلفن، شعبه — آخرین ۴۰۰ تماس در ۹۰ روز.
| کد | خطا | چه باید کرد |
|---|---|---|
| 401 | api_key_missing، api_key_invalid |
کلید وجود ندارد، لغو شده یا منقضی شده است؛ توکن OAuth منقضی شده — آن را تازه کنید |
| 403 | scope_required |
کلید آن دسترسی را ندارد — آن را در «دسترسیها» اضافه کنید |
| 400 | location_required |
کلید چند شعبه دارد — location را ارسال کنید |
| 404 | location_not_found |
شعبه وجود ندارد یا کلید به شعبههای دیگری محدود شده است |
| 429 | rate_limited |
محدودیت تمام شده، پس از Retry-After ثانیه دوباره تلاش کنید |
رویدادهای تماس#
در زمان واقعی — وبهوکهای مرکز تلفن: تلفنی → API و MCP → وبهوکها یا POST /v1/webhooks با کلیدی که مجوز webhooks:write دارد. روی نشانی https شما در عرض چند ثانیه برای هر رویداد یک POST میآید: call.started (آغاز شد: جهت، چه کسی، به کجا، خط)، call.ringing (زنگ خوردن برای چه کسی — یکی برای هر تلفن)، call.answered (چه کسی پاسخ داد)، call.transferred (چه کسی و به چه کسی انتقال داد)، call.ended (نتیجه، مدت، گفتگو، چه کسی پاسخ داد). وبهوک را میتوان به شعبهها و انواع رویداد محدود کرد.
{ "id": "1727771234.56:2", "type": "call.answered", "createdAt": "2026-10-01T10:00:05Z",
"locationId": "…", "webhookId": "wh_…", "attempt": 1,
"data": { "callId": "1727771234.56", "seq": 2, "direction": "inbound",
"from": { "number": "+995555123456" }, "party": { "extension": "101", "name": "Анна" } } }
امضا — سرآیند X-Cenaly-Signature: t=<زمان unix>,v1=<HMAC-SHA256 از "t.بدنه" با رمز وبهوک>. دوباره محاسبه کنید، در زمان ثابت مقایسه کنید و t قدیمیتر از 5 دقیقه را رد کنید. رمز whsec_… فقط یک بار نشان داده میشود؛ «رمز جدید» رمز پیشین را بیدرنگ باطل میکند.
تحویل — ظرف 10 ثانیه با 2xx پاسخ دهید. در غیر این صورت با فاصلههای 10 ثانیه، 30 ثانیه، 2، 5، 10، 15 و 15 دقیقه دوباره میفرستیم (8 تلاش، حدود یک ساعت)؛ ارسال دوباره همان id را دارد — با آن موارد تکراری را کنار بگذارید. گزارش تحویلها (کد پاسخ، زمان، تلاش) در پنجره وبهوک و GET /v1/webhooks/{id}/deliveries است؛ «بررسی» یک webhook.ping خدماتی میفرستد. اگر نشانی 3 شبانهروز پیاپی هیچ تحویلی را نپذیرد، وبهوک خودش خاموش میشود: برای مالک ایمیل میآید، در پنجره «وبهوکها» نشان «بهطور خودکار خاموش شد» و دکمه «روشن کردن» ظاهر میشود (یا PATCH /v1/webhooks/{id} با { "enabled": true }).
بدون سرور خودتان — همان جریان با نظرسنجی: GET /v1/events?since=<id آخرین رویداد> یا ابزار MCP با نام get_call_events (رویدادهای شعبه در 7 روز گذشته، تا 2000؛ در هر پاسخ تا 500، more: true — با همان since جلوتر بروید).
پس از پردازش ضبط — تماس همراه با رونویسی و تحلیل از طریق وبهوک منبع «وبهوک» در بخش «تماسها» میآید.
«باز / بسته» — PUT /v1/open-closed با { "closed": true } شعبه را تا پایان شبانهروز میبندد (مانند *28 از تلفن: تماسها با قواعد «خارج از ساعت کاری» انجام میشوند)، false آن را باز میکند؛ GET نشان میدهد آیا بسته است و توسط چه کسی. با "until" — تا آن لحظه بسته است (نه بیشتر از 30 روز)، سپس خودش باز میشود: زمان بدون جابهجایی (2026-10-05T09:00) در منطقه زمانی شعبه خوانده میشود؛ false آن را هم برمیدارد. تیک «بستن با کد *28» در مسیریابی باید فعال باشد (در غیر این صورت 409).
امنیت#
- کلید یک بار نشان داده میشود و نزد ما فقط بهصورت اثر انگشت نگهداری میشود؛ کلید افشاشده با یک دکمه باطل میشود.
- اتصال OAuth را فقط مالک میتواند مجاز کند، و مشخص است که دسترسی به کدام نشانی داده میشود؛ اتصال مجاز را میتوان به مجوزها و شعبهها محدود کرد و هر لحظه لغو کرد.
- شمارههای تلفن دادههای شخصی مشتریان شما هستند: مجوز دسترسی به گزارش و ضبطها را فقط به یکپارچهسازیهایی بدهید که واقعاً به آن نیاز دارند.
- همه تغییرات از طریق کلید یا اتصال در گزارش اقدامات مرکز تلفن با نام کلید یا برنامه ثبت میشود.