وبسرویس مرکز تماس
از اولین درخواست تا اتصال کامل CRM؛ تماس بسازید، نتیجه را دنبال کنید و گزارش، ضبط و وضعیت داخلیها را در نرمافزار خود داشته باشید.
معرفی و انتخاب مسیر درست#
وبسرویس، رابط ارتباط نرمافزار شما با مرکز تماس است. درخواست را از سرور CRM، ERP یا برنامه خود ارسال میکنید و پاسخ JSON میگیرید. برای دریافت خودکار اتفاقات تماس، وبهوک را در کنار آن فعال کنید.
کلیک برای تماس، قطع، پخش صدا، انتقال و کنفرانس.
تاریخچه تماس، ضبط، صندوق صوتی و شاخصهای مرکز.
تماس صوتی آماده، OTP فارسی و عضویت داخلی در صف.
موضوعات راهنمای PBX V1 اینجا هم پوشش داده شدهاند؛ تفاوت شناسهها، پاسخ غیرهمزمان فرمانها و مسیر سازگاری در بخش مهاجرت توضیح داده شده است.
آدرس پایه و احراز هویت#
https://api.hamkaran.cloud/api/hamkaran/v2
در پنل همان مرکز تماس، اتصال «وبسرویس» را فعال و کلید آن را دریافت کنید. در تمام درخواستها Header با نام key را ارسال کنید. دادههای POST را به صورت JSON بفرستید.
key: YOUR_WEBSERVICE_KEY Accept: application/json Content-Type: application/json
| هدر | چه زمانی لازم است؟ | کاربرد |
|---|---|---|
key | تمام درخواستها | کلید اتصال وبسرویس همین مرکز تماس |
Accept | پیشنهاد میشود | application/json برای دریافت پاسخ و خطای JSON |
Content-Type | POST با JSON | application/json |
Idempotency-Key | فرمانهای تماس | شناسه درخواست تکرارپذیر، ۸ تا ۱۶۰ کاراکتر؛ کنترل صف قرارداد جداگانه دارد. |
شروع سریع؛ اولین درخواست بدون ایجاد تماس#
- کلید اتصال را آماده کنید.مرکز باید PBX V2 و اتصال وبسرویس فعال باشد؛ IP سرور شما هم باید در محدوده مجاز اتصال باشد.
- وضعیت داخلیها را بخوانید.درخواست زیر هیچ گوشی را زنگ نمیزند و برای بررسی اتصال مناسب است.
- پاسخ را بررسی کنید.HTTP 200 و آرایه داخلیها یعنی درخواست مجاز بوده است.
registered: falseبه وضعیت گوشی مربوط است، نه الزاماً خطای کلید.
export HAMKARAN_WEBSERVICE_KEY='YOUR_WEBSERVICE_KEY' curl --request GET 'https://api.hamkaran.cloud/api/hamkaran/v2/extension' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json'
{
"status": "success",
"data": [
{
"extension": "200",
"registered": true,
"state": "NOT_INUSE",
"observed_at": 1789545600
}
]
}شمارهها، زمانها و UUIDهای مثالها ساختگیاند. آنها را با داده واقعی مرکز خود جایگزین کنید.
شناسه درخواست، تماس و کانال#
| شناسه | معنا | از کجا دریافت میشود؟ |
|---|---|---|
operation_id | عملیات درخواستشده از API؛ برای پیگیری اجرای فرمان | پاسخ ثبت فرمان؛ نامهای action_id و actionId هم برگردانده میشوند. |
call_id | شناسه مشترک تماس در گزارش و وبهوک | نتیجه عملیات ایجاد تماس، گزارش یا رویداد تماس |
leg_id | شناسه یک کانال مشخص در مکالمه | رویدادهای زنده مانند call.connected؛ کانال مقابل در data.other_leg_id میآید. |
recording_id | شناسه ضبط عضو کنفرانس | رویداد ضبط یا recordings[].id در گزارش |
شناسههای PBX V2 از نوع UUID هستند. آنها را رشته نگه دارید؛ شناسه قدیمی Asterisk را جایگزین نکنید. برای انتقال و کنفرانس، شناسه کانال مربوط به داخلی انتقالدهنده یا میزبان را از رویدادهای همان تماس نگه دارید.
جلوگیری از تماس تکراری#
برای هر عملیات منطقی جدید یک Idempotency-Key تازه بسازید. اگر پاسخ شبکه گم شد، همان Body را با همان کلید دوباره ارسال کنید. برای تلاش مجدد کلید تازه تولید نکنید؛ کلید تازه یعنی عملیات تازه.
Idempotency-Key: crm-ticket-4821-call-001
- تکرار درخواست معتبر با همان کلید و همان پارامترها، همان عملیات را برمیگرداند؛ مجوز و معتبر بودن منابع همچنان بررسی میشود.
- استفاده از همان کلید برای فرمان یا پارامتر متفاوت، پاسخ
409میدهد. - دامنه کلید، اتصال وبسرویس شماست؛ نگهداری پیشفرض عملیات نهایی ۳۰ روز است. درخواست قدیمی را خارج از این بازه بیبررسی تکرار نکنید.
- برای فرمانهای صف، UUID داخل فیلد
idنقش شناسه تکرار را دارد؛ قرارداد صف را ببینید.
کدهای HTTP و خطاها#
| کد | معنا | اقدام پیشنهادی |
|---|---|---|
200 | خواندن موفق داده یا دریافت فایل | محتوای پاسخ را متناسب با endpoint پردازش کنید. |
202 | فرمان ثبت و پذیرفته شده است | نتیجه را با شناسه عملیات پیگیری کنید؛ هنوز به معنی پاسخ مخاطب نیست. |
403 | کلید، IP، نوع مرکز یا دسترسی نامعتبر | وضعیت اتصال و محدودیت داخلی/خط را بررسی کنید. |
404 | تماس، عملیات یا فایل پیدا نشد | شناسه و مالکیت را بررسی کنید؛ تماس فعال ممکن است پایان یافته باشد. |
405 | روش HTTP اشتباه | فرمانهای تماس باید با POST ارسال شوند. |
409 | تعارض کلید تکرار | همان کلید را با پارامتر متفاوت استفاده نکنید. |
422 | ورودی ناقص یا نامعتبر | نوع فیلدها، UUID، بازه تاریخ و شمارهها را اصلاح کنید. |
429 | سقف درخواست یا صف پر | با فاصله و تأخیر تصادفی تلاش مجدد کنید؛ از حلقه سریع خودداری کنید. |
502 / 503 | گزارش در دسترس نیست یا سرویس این مرکز فعال نیست | با زمان درخواست و شناسه عملیات از پشتیبانی پیگیری کنید. |
500 | خطای داخلی | برای عملیات تماس وضعیت را بررسی کنید؛ بدون کلید ثابت دوباره شمارهگیری نکنید. |
{
"message": "The given data was invalid.",
"errors": {
"timeout": ["The timeout must be between 5 and 60."]
}
}متن خطا ممکن است براساس زبان سرویس متفاوت باشد. بعضی خطاها فقط message دارند؛ برنامه را به وجود همیشگی errors وابسته نکنید.
دریافت گزارش تماسها#
فهرست تماسهای همین مرکز را با صفحهبندی، فیلتر و مرتبسازی بگیرید. گزارش نهایی شامل مقصد نهایی، وضعیت اتصال، زمان انتظار و مکالمه، نام مخاطب و ضبطهای موجود است.
| پارامتر Query | نوع / پیشفرض | توضیح |
|---|---|---|
date_from، date_to | رشته تاریخ | فرمت YYYY-MM-DD میلادی یا شمسی؛ پیشفرض از هفت روز قبل تا امروز، براساس ایران. روز پایان هم در بازه است. فاصله دو تاریخ حداکثر ۹۳ روز. |
datefrom، dateto | نام جایگزین | برای سازگاری پذیرفته میشوند؛ فقط یکی از دو قالب نامگذاری را استفاده کنید. |
page | عدد؛ ۱ | شماره صفحه از ۱ تا ۱۰۰۰۰۰ |
limit | عدد؛ ۲۵ | تعداد رکورد هر صفحه، بین ۱ تا ۱۰۰ |
source | رشته شماره | تطبیق دقیق شماره تماسگیرنده؛ فرمت ایرانی برای جستوجو یکسانسازی میشود. |
internalnumber | رشته؛ ۱ تا ۴ رقم | گزارش مربوط به داخلی؛ باید در دسترسی کلید باشد. |
direction | in / out / int | ورودی / خروجی / داخلی |
answered | 0 / 1 | وضعیت نهایی ناموفق / موفق؛ پاسخ IVR بهتنهایی معیار موفقیت نیست. |
sort | date | date / duration / talk / caller / destination |
order | desc | asc برای صعودی یا desc برای نزولی |
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/reports' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'date_from=2026-09-09' \ --data-urlencode 'date_to=2026-09-16' \ --data-urlencode 'internalnumber=200' \ --data-urlencode 'direction=in' \ --data-urlencode 'page=1' \ --data-urlencode 'limit=25' \ --data-urlencode 'sort=date' \ --data-urlencode 'order=desc'
{
"data": [
{
"call_id": "11111111-1111-4111-8111-111111111111",
"caller": "9120000001",
"callee": "200",
"call_date": "2026-09-16 10:30:00",
"direction": "in",
"answered": 1,
"wait_sec": 12,
"ring_sec": 6,
"bill_sec": 45,
"duration_sec": 57,
"hangup_cause": "NORMAL_CLEARING",
"identity": {"name": "مخاطب نمونه", "source": "contacts"},
"destination_identity": null,
"recordings": []
}
],
"total": 1,
"page": 1,
"limit": 25
}| فیلد پاسخ | تفسیر |
|---|---|
caller / callee | شماره مبدأ / مقصد نهایی ثبتشده. شمارهها رشتهاند؛ شماره ایرانی در گزارش بدون ۹۸ و صفر ابتدایی است. |
wait_sec / ring_sec / bill_sec / duration_sec | بهترتیب زمان انتظار، زنگ، مکالمه و طول کل تماس، برحسب ثانیه؛ این مقادیر لزوماً اجزای قابل جمع یکدیگر نیستند. |
queue_id / queue_name / agent | اطلاعات صف و پاسخدهنده، در صورت ثبت |
terminal_type / attempted_destination / endpoint_status | نوع مقصد پایانی، مقصد تلاششده و نتیجه endpoint؛ برای تحلیل تماس بدون پاسخ مفیدند. |
identity / destination_identity | اطلاعات نام شناساییشده مبدأ و مقصد؛ ممکن است null باشد. |
recordings | آرایه فایلهای آماده؛ خالی بودن یعنی اکنون فایل قابل دریافت در پاسخ نیست. |
revision | نسخه حسابداری رکورد؛ اطلاعات تکمیلی ممکن است بعداً برسد. |
برای پیمایش، تا وقتی page × limit < total است صفحه بعد را بخوانید. چون دادهها در حال تغییرند، هنگام دریافت چند صفحه شناسه call_id را در نرمافزار خود یکتا نگه دارید.
call.cdr و برای فایل، recording.ready را دریافت کنید.جزئیات یک تماس#
با شناسه تماس، آخرین رکورد گزارش همان تماس را دریافت کنید. این endpoint گزارش ثبتشده را میخواند؛ فهرست کانالهای زنده نیست.
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/call' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'call_id=11111111-1111-4111-8111-111111111111'
پاسخ HTTP 200 یک آبجکت تماس با همان فیلدهای گزارش و دادههای تفصیلی موجود است. UUID نامعتبر ۴۲۲، نبود رکورد ۴۰۴ و محدودیت داخلی ۴۰۳ دارد.
داشبورد مرکز تماس#
شاخصهای تجمیعی تماس، مقایسه بازه قبل، روند روزانه و ساعتی، داخلیها، صفها و کیفیت ثبتشده را دریافت کنید. تاریخهای date_from و date_to یا نامهای سازگار datefrom و dateto پذیرفته میشوند.
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/dashboard' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'date_from=2026-09-09' \ --data-urlencode 'date_to=2026-09-16'
| بخش پاسخ | محتوا |
|---|---|
range / previous_range | بازه انتخابشده و بازه مقایسه |
current / previous | شاخصهای تجمیعی هر بازه |
directions | تفکیک ورودی، خروجی و داخلی |
daily / hourly | روند روزانه و توزیع ساعتهای روز |
internals / queues | آمار داخلیها و صفها |
quality / recent_missed | کیفیت اندازهگیریشده و تماسهای ازدسترفته اخیر |
generated_at / data_until / restricted | زمان تولید، مرز داده و محدود بودن پاسخ به دسترسی داخلیهای کلید |
بازه داشبورد حداکثر ۹۰ روز است و روز پایان نباید آینده باشد. داده داشبورد کوتاهمدت کش میشود؛ برای پایش لحظهای زنگ و اتصال از وبهوک استفاده کنید. نبود اندازهگیری کیفیت را معادل کیفیت صفر نگیرید.
وضعیت داخلیها#
فقط داخلیهای مجاز برای کلید شما برگردانده میشوند. نمونه درخواست و پاسخ کامل در شروع سریع آمده است.
| فیلد / مقدار | معنا |
|---|---|
extension | شماره کوتاه داخلی، مانند رشته «200» |
registered | آخرین وضعیت مشاهدهشده رجیستر بودن گوشی |
NOT_INUSE | داخلی رجیستر است و در snapshot اشغال نیست. |
INUSE | داخلی در snapshot اشغال است. |
UNAVAILABLE | داخلی در snapshot رجیستر نیست. |
UNKNOWN | اطلاعات زنده در دسترس نیست؛ با آزاد بودن داخلی متفاوت است. |
observed_at | Unix timestamp مشاهده وضعیت، یا null در نبود داده |
وضعیت بهصورت دورهای تازه میشود. پیش از ساخت تماس، بررسی این فیلد مفید است اما ثبت نهایی فرمان هم دسترسی و رجیستر بودن را دوباره بررسی میکند.
دریافت ضبط تماس و کنفرانس#
پاسخ موفق این endpoint فایل صوتی است، نه JSON. برای ضبط اصلی فقط call_id را بفرستید.
curl --fail-with-body --request POST \
'https://api.hamkaran.cloud/api/hamkaran/v2/get_record' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{"call_id":"11111111-1111-4111-8111-111111111111"}' \
--output call-record.wav| مقدار track | فایل درخواستی |
|---|---|
| ارسال نشود | ضبط اصلی تماس؛ مقدار main را به عنوان track نفرستید. |
mixed | ضبط مشترک کنفرانس |
| UUID ضبط عضو | ضبط جداگانه عضو؛ از recordings[].id استفاده کنید، نه شماره عضو. |
voicemail | پیام صندوق صوتی مربوط به تماس |
{
"call_id": "11111111-1111-4111-8111-111111111111",
"track": "mixed"
}روش دیگر استفاده از recordings[].url در پاسخ گزارش است. این لینک امضاشده حدود ۱۵ دقیقه اعتبار دارد؛ آن را محرمانه نگه دارید. برای لینک تازه، گزارش تماس را دوباره بگیرید. وجود تماس، وجود ضبط را تضمین نمیکند؛ فایل آمادهنشده یا ناموجود پاسخ ۴۰۴ دارد.
فهرست پیامهای صندوق صوتی#
رویدادهای پیام صندوق صوتی ثبتشده را با صفحهبندی ۲۵تایی دریافت کنید. این endpoint به کلید با دسترسی کامل مرکز نیاز دارد؛ کلید محدود به داخلی پاسخ ۴۰۳ میگیرد.
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/voicemails' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'page=1'
پاسخ صفحهبندی Laravel است: رویدادها در data، صفحه در current_page، تعداد در total و آخرین صفحه در last_page. هر رویداد شناسه call_id دارد؛ برای دریافت صوت، آن را با track: voicemail به get_record بدهید.
ایجاد تماس؛ Click to Call#
ابتدا داخلی کارشناس زنگ میخورد؛ پس از پاسخ او، مقصد شمارهگیری میشود. مقصد میتواند داخلی همان مرکز یا شماره بیرونی باشد.
| فیلد | نوع / الزام | توضیح |
|---|---|---|
src | رشته؛ الزامی | شماره داخلی مجاز و رجیسترشده؛ مانند «200» |
dest | رشته؛ الزامی | داخلی مقصد یا شماره تلفن؛ مانند «09120000001» |
timeout | عدد؛ اختیاری | مهلت شمارهگیری بین ۵ تا ۶۰ ثانیه |
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/create_call' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-call-001' \
--data '{"src":"200","dest":"09120000001","timeout":30}'{
"operation_id": "22222222-2222-4222-8222-222222222222",
"action_id": "22222222-2222-4222-8222-222222222222",
"actionId": "22222222-2222-4222-8222-222222222222",
"status": "queued",
"result": null
}call.connected و برای نتیجه نهایی، CDR را بخوانید.پیگیری نتیجه فرمان#
شناسهای که از ثبت فرمان گرفتهاید را با همان کلید اتصال ارسال کنید. این عملیات متعلق به همان اتصال است؛ کلید دیگری لزوماً به آن دسترسی ندارد.
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/operations' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'operation_id=22222222-2222-4222-8222-222222222222'
{
"operation_id": "22222222-2222-4222-8222-222222222222",
"action_id": "22222222-2222-4222-8222-222222222222",
"actionId": "22222222-2222-4222-8222-222222222222",
"status": "succeeded",
"result": {
"call_id": "11111111-1111-4111-8111-111111111111",
"state": "accepted",
"job_id": "33333333-3333-4333-8333-333333333333"
}
}| status | معنا و اقدام |
|---|---|
queued / running | در انتظار یا در حال پردازش؛ با فاصله زمانی وضعیت را دوباره بخوانید. |
succeeded | فرمان اجرا/پذیرفته شده است؛ result را بخوانید. accepted به معنی پاسخ مخاطب نیست. |
failed | اجرای فرمان شکست خورده؛ کد علت در result.error است. |
expired | فرمان اجرانشده از مهلت ۹۰ثانیهای عبور کرده است. |
unknown | نتیجه اجرا قطعی نیست؛ پیش از درخواست تازه، رویدادها و گزارش را بررسی کنید. شمارهگیری خودکار مجدد نکنید. |
نمونه کد دارای polling محدود و کنترل timeout در بخش Node.js و Laravel آمده است.
قطع تماس فعال#
برای قطع کانال اصلی، فقط call_id کافی است. برای کانال مشخص leg_id را هم ارسال کنید. کلید محدود به داخلی باید leg_id همان داخلی مجاز را بدهد.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/hang_up_call' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-hangup-001' \
--data '{"call_id":"11111111-1111-4111-8111-111111111111"}'پاسخ ۲۰۲ همان ساختار عملیات است. اگر تماس بین ثبت و اجرا تمام شود، ممکن است نتیجه عملیات failed با call_not_active باشد.
پخش فایل روی تماس#
فایل موجود در بانک محتوای همین مرکز را روی کانال انتخابی پخش کنید. audio باید نام، file_id یا شناسه فایل مجاز باشد؛ URL دلخواه یا مسیر سرور پذیرفته نمیشود.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/play_audio_on_channel' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-audio-001' \
--data '{
"call_id":"11111111-1111-4111-8111-111111111111",
"leg_id":"44444444-4444-4444-8444-444444444444",
"audio":"welcome.wav"
}'call_id و audio الزامیاند. leg_id برای کلید کامل اختیاری است و در صورت حذف، کانال اصلی انتخاب میشود. پاسخ، عملیات قابل پیگیری است.
انتقال مستقیم یا با مشورت#
کانال داخلی انتقالدهنده را مشخص و تماس را به داخلی مقصد منتقل کنید. blind برای انتقال مستقیم و attended برای انتقال با مشورت است. در این API مقصد انتقال باید داخلی باشد؛ دعوت شماره بیرونی به کنفرانس endpoint جدا دارد.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/transfer' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-transfer-001' \
--data '{
"call_id":"11111111-1111-4111-8111-111111111111",
"leg_id":"44444444-4444-4444-8444-444444444444",
"dest":"201",
"mode":"attended"
}'برای انتقال مستقیم مقدار mode را blind کنید. شروع، اتصال مقصد و خطا از رویدادهای transfer.started، transfer.completed و transfer.failed دنبال میشوند؛ ثبت فرمان پایان فرایند انتقال نیست.
ساخت و مدیریت کنفرانس#
از مکالمه متصلشده داخلی شروع کنید. ابتدا آن را به کنفرانس ببرید، سپس پس از مشاهده رویداد ایجاد/عضویت، شرکتکننده داخلی یا موبایل را دعوت کنید. نمونه زیر از کانال داخلی میزبان استفاده میکند.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/conference_start' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-room-001' \
--data '{
"call_id":"11111111-1111-4111-8111-111111111111",
"leg_id":"44444444-4444-4444-8444-444444444444"
}'curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/conference_invite' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: crm-ticket-4821-invite-001' \
--data '{
"call_id":"11111111-1111-4111-8111-111111111111",
"leg_id":"44444444-4444-4444-8444-444444444444",
"dest":"09120000001"
}'| POST endpoint | فیلدهای Body | کانال مورد استفاده |
|---|---|---|
/conference_start | call_id، leg_id | داخلی حاضر در مکالمه متصلشده |
/conference_invite | call_id، leg_id، dest | میزبان؛ مقصد داخلی یا شماره بیرونی است. |
/conference_mute | call_id، leg_id، muted | عضوی که میکروفنش باید تغییر کند؛ muted از نوع boolean است. |
/conference_kick | call_id، leg_id | عضوی که باید از کنفرانس خارج شود. |
{
"call_id": "11111111-1111-4111-8111-111111111111",
"leg_id": "55555555-5555-4555-8555-555555555555",
"muted": true
}برای وصل میکروفن muted را false کنید. برای خروج عضو همین شناسهها را به conference_kick بفرستید. هر فرمان باید Idempotency-Key مستقل داشته باشد. عضویت واقعی را با conference.member_joined تأیید کنید؛ موفقیت دعوت به معنی پاسخ مخاطب نیست.
ضبط مشترک و ضبط اعضای موجود از recordings گزارش و get_record دریافت میشوند؛ وجود فایل هر عضو را از پاسخ بخوانید، نه از روی حدس شماره تلفن.
ارسال تماس از پیش ضبطشده#
از یک خط متعلق به مرکز تماس، با مقصد تماس بگیرید و پس از پاسخ، فایل بانک محتوا را پخش کنید. این فرمان نیازمند کلید با دسترسی کامل مرکز است.
| فیلد | الزام / نوع | توضیح |
|---|---|---|
src | الزامی؛ رشته | شماره خط متعلق به مرکز؛ مانند «02190000000» |
dest | الزامی؛ رشته | شماره مخاطب |
audio | الزامی؛ رشته | نام، شناسه یا file_id فایل صوتی در بانک محتوای همین مرکز |
timeout | اختیاری؛ عدد | ۵ تا ۶۰ ثانیه |
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/send-pre-recorded' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: reminder-order-4821-001' \
--data '{"src":"02190000000","dest":"09120000001","audio":"reminder.wav","timeout":30}'پیگیری تماس صوتی آماده#
برای حفظ نام endpoint آشنا در PBX V1، این مسیر هم وجود دارد. در PBX V2 پاسخ آن وضعیت عملیات است؛ برای نتیجه مکالمه، call_id داخل result را در گزارش بررسی کنید.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/get-pre-recorded-call-detail' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"actionId":"22222222-2222-4222-8222-222222222222"}'این درخواست خواندنی است و Idempotency-Key نیاز ندارد. پاسخ همان ساختار operation_id، status و result در پیگیری فرمان است. برای اتصال تازه میتوانید مستقیماً از operations استفاده کنید.
ارسال کد تأیید صوتی فارسی#
پس از پاسخ مقصد، پیام «رمز یکبارمصرف شما» پخش و ارقام کد فارسی خوانده میشوند. پس از یک ثانیه مکث، پیام تکرار پخش میشود و همان کد یک بار دیگر رقمبهرقم خوانده میشود. src و dest رشته شماره و code رشته ۳ تا ۸ رقم انگلیسی است. برای حفظ صفر اول، کد را عدد JSON نفرستید.
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/send-otp' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: verification-session-4821-001' \
--data '{"src":"02190000000","dest":"09120000001","code":"048291","timeout":30}'src الزامی و متعلق به مرکز است؛ کلید محدود به داخلی مجاز نیست. timeout اختیاری و ۵ تا ۶۰ ثانیه است. نتیجه ارسال مانند سایر فرمانها پیگیری میشود. مقدار OTP وارد لاگ و ضبط این مسیر نمیشود.
عضویت و وضعیت داخلی در صف#
عضویت داینامیک همان صفهایی کنترل میشود که مدیر در سناریو تعریف کرده است. داخلی باید عضو مجاز داینامیک صف باشد؛ API مجوز تازهای ایجاد نمیکند.
| روش / endpoint | کاربرد | دسترسی |
|---|---|---|
GET /queues | snapshot صفها و اعضا | کلید کامل مرکز |
POST /queue_control | ورود، خروج، استراحت یا پایان استراحت | داخلی در محدوده مجاز کلید |
GET /queue_operation?id=UUID | پیگیری نتیجه همان فرمان صف | کلید کامل مرکز |
curl --request POST 'https://api.hamkaran.cloud/api/hamkaran/v2/queue_control' \
--header "key: $HAMKARAN_WEBSERVICE_KEY" \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"id":"66666666-6666-4666-8666-666666666666",
"extension":"200",
"action":"join",
"queue_code":"21"
}'id یک UUID تازه برای عملیات منطقی است؛ در تلاش مجدد همان id را بفرستید. action یکی از join، leave، break یا resume است. برای ورود/خروج، کد واقعی صف را مشخص کنید؛ استراحت/پایان استراحت وضعیت داخلی را در صفهایش تغییر میدهد.
curl --get 'https://api.hamkaran.cloud/api/hamkaran/v2/queue_operation' \ --header "key: $HAMKARAN_WEBSERVICE_KEY" \ --header 'Accept: application/json' \ --data-urlencode 'id=66666666-6666-4666-8666-666666666666'
HTTP 202 ثبت درخواست است؛ نتیجه اعمال واقعی را پیگیری کنید. خروج از صف و استراحت، مکالمه جاری داخلی را قطع نمیکند.
نمونه کامل Node.js و PHP / Laravel#
این نمونهها از کلید ذخیرهشده روی سرور استفاده میکنند. برای اجرای مثال ایجاد تماس، داخلی و مقصد واقعی خود را جایگزین کنید؛ اجرای آن گوشیها را زنگ میزند.
Node.js؛ ثبت و پیگیری تماس
برای Node.js دارای fetch داخلی، مانند نسخه ۲۰ یا جدیدتر. کلید درخواست را در رکورد CRM ذخیره کنید تا تلاش مجدد پس از timeout همان عملیات را دنبال کند.
import { setTimeout as sleep } from 'node:timers/promises';
const base = 'https://api.hamkaran.cloud/api/hamkaran/v2';
const key = process.env.HAMKARAN_WEBSERVICE_KEY;
if (!key) throw new Error('HAMKARAN_WEBSERVICE_KEY is required');
async function request(path, { body, requestId } = {}) {
const response = await fetch(base + path, {
method: body ? 'POST' : 'GET',
headers: {
key,
Accept: 'application/json',
...(body ? { 'Content-Type': 'application/json' } : {}),
...(requestId ? { 'Idempotency-Key': requestId } : {}),
},
...(body ? { body: JSON.stringify(body) } : {}),
signal: AbortSignal.timeout(15000),
});
const data = await response.json();
if (!response.ok) {
// Do not log request headers or OTP values.
throw new Error('HTTP ' + response.status + ': ' + (data.message || 'API error'));
}
return data;
}
// Persist this value with the CRM task. Reuse it after a network timeout.
const requestId = 'crm-ticket-4821-call-001';
let operation = await request('/create_call', {
body: { src: '200', dest: '09120000001', timeout: 30 },
requestId,
});
for (let attempt = 0; attempt < 10; attempt++) {
if (!['queued', 'running'].includes(operation.status)) break;
await sleep(5000);
operation = await request(
'/operations?' + new URLSearchParams({ operation_id: operation.operation_id })
);
}
console.log({
operation_id: operation.operation_id,
status: operation.status,
call_id: operation.result?.call_id,
});
// "succeeded" + "accepted" is not proof of an answered call.
// Continue with call.connected / call.cdr webhooks.
// If still queued/running, retain operation_id and check later.
// Never automatically redial an "unknown" operation.Node.js؛ گزارش و دریافت فایل
کد زیر را میتوانید در همان ماژول بالا، به جای بخش ساخت تماس، استفاده کنید. برای دانلود، به شناسه call_id یک گزارش آماده نیاز دارید.
import { writeFile } from 'node:fs/promises';
const query = new URLSearchParams({
date_from: '2026-09-09',
date_to: '2026-09-16',
page: '1',
limit: '25',
});
const report = await request('/reports?' + query);
console.log({ total: report.total, page: report.page });
const callId = '11111111-1111-4111-8111-111111111111';
const response = await fetch(base + '/get_record', {
method: 'POST',
headers: { key, 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({ call_id: callId }),
signal: AbortSignal.timeout(30000),
});
if (!response.ok) throw new Error('Recording HTTP ' + response.status);
await writeFile('call-record.wav', Buffer.from(await response.arrayBuffer()));
// Store recordings in private storage. For large files, stream to disk.PHP / Laravel؛ تنظیم کلید و ساخت تماس
در متغیر محیطی برنامه خود HAMKARAN_WEBSERVICE_KEY را تعریف کنید؛ سپس آن را از config بخوانید.
return [
// Other service configurations...
'hamkaran' => [
'key' => env('HAMKARAN_WEBSERVICE_KEY'),
'base_url' => 'https://api.hamkaran.cloud/api/hamkaran/v2',
],
];use Illuminate\Support\Facades\Http;
$base = config('services.hamkaran.base_url');
$key = config('services.hamkaran.key');
$requestId = 'crm-ticket-4821-call-001'; // Persist with the CRM task.
$response = Http::withHeaders([
'key' => $key,
'Accept' => 'application/json',
'Idempotency-Key' => $requestId,
])->connectTimeout(3)->timeout(15)->post($base . '/create_call', [
'src' => '200',
'dest' => '09120000001',
'timeout' => 30,
]);
$response->throw();
$operation = $response->json();
$operationId = $operation['operation_id'];
// In a later queued job, query the same operation.
// Do not keep a web request blocked while waiting for a call.
$result = Http::withHeaders([
'key' => $key,
'Accept' => 'application/json',
])->connectTimeout(3)->timeout(15)->get($base . '/operations', [
'operation_id' => $operationId,
])->throw()->json();
// queued/running: schedule another bounded check.
// unknown: reconcile with call events before any new request.
// succeeded: inspect result; accepted is not an answered call.PHP / Laravel؛ گزارش و ضبط
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
$headers = [
'key' => config('services.hamkaran.key'),
'Accept' => 'application/json',
];
$base = config('services.hamkaran.base_url');
$report = Http::withHeaders($headers)->timeout(20)
->get($base . '/reports', [
'date_from' => '2026-09-09',
'date_to' => '2026-09-16',
'internalnumber' => '200',
'page' => 1,
'limit' => 25,
])->throw()->json();
$recording = Http::withHeaders($headers)->timeout(30)
->post($base . '/get_record', [
'call_id' => '11111111-1111-4111-8111-111111111111',
// 'track' => 'mixed', // Optional conference mix.
])->throw();
// Use a private disk; do not publish the recording URL.
Storage::disk('local')->put('private/calls/example.wav', $recording->body());مثالهای دانلود برای فایلهای کوچکاند. برای فایلهای طولانی، از streaming و سقف اندازه متناسب با برنامه خود استفاده کنید.
مهاجرت از PBX V1 و مسیر سازگاری#
نسخه مرکز تماس با شماره مسیر API یکی نیست. مراکز PBX V1 همچنان مسیر قبلی را دارند. درخواست مسیر قدیمی برای یک مرکز PBX V2 توسط پردازشگر PBX V2 انجام میشود؛ برای اتصال جدید، مسیر صریح v2 را انتخاب کنید.
| موضوع | PBX V1 / اتصال قبلی | PBX V2 |
|---|---|---|
| آدرس API | /api/hamkaran/v1/ | /api/hamkaran/v2/؛ مسیر قدیمی برای مرکز V2 نیز قابل استفاده است. |
| شناسه تماس | شناسه اعلامشده در قرارداد V1 | UUID؛ شناسه Asterisk را منتقل نکنید. |
| پاسخ فرمان | قرارداد قبلی | ۲۰۲ و operation_id؛ در مسیر سازگاری ۲۰۰، همراه همان عملیات قابل پیگیری |
| نام پارامتر مقصد | dst یا dest | dest؛ dst نیز پذیرفته میشود. |
| شناسه ورودی تماس | uid / channel_id | به call_id نگاشت میشوند؛ برای کانال مشخص leg_id را جدا ارسال کنید. |
| کد صوتی | otp یا code | code؛ otp نیز پذیرفته میشود. src خط الزامی است. |
| جزئیات تماس صوتی | ساختار قرارداد V1 | وضعیت عملیات؛ نتیجه مکالمه از گزارش یا وبهوک |
| گزارش در مسیر قدیمی | ساختار قبلی | برای مرکز V2، نگاشت سازگاری در data.rows ارائه میشود؛ مسیر جدید data/total/page/limit دارد. |
| جلوگیری از تکرار | بسته به اتصال قبلی | Idempotency-Key ثابت برای retry. مسیر قدیمی در نبود هدر کلید تازه میسازد؛ این حالت جلوی تکرار CRM را نمیگیرد. |
دسترسی، محدودیت و طراحی اتصال#
- پیشفرض سقف درخواست هر کلید ۱۲۰ درخواست در دقیقه است؛ در تنظیمات اتصال بین ۱ تا ۶۰۰۰ قابل تنظیم است. کد polling را با سهم درخواست خود تنظیم کنید.
- کلید را به IP و داخلیهای مورد نیاز محدود کنید. کنترل کانال با کلید محدود، نیازمند leg_id همان داخلی مجاز است.
- تماس صوتی خودکار، فهرست صندوق صوتی، snapshot صفها و خواندن عملیات صف به کلید کامل مرکز نیاز دارند.
- برای هر مرکز حداکثر ۱۰۰ فرمان queued پذیرفته میشود. ۴۲۹ را با انتظار و backoff مدیریت کنید، نه حلقه تکرار فوری.
- شمارهها و کدها را رشته و با ارقام انگلیسی ارسال کنید. برای نمایش، خروجی عددی رشته را به عدد زبان برنامهنویسی تبدیل نکنید.
- از وبهوک برای اتفاقات زنده و از گزارش برای حسابداری نهایی استفاده کنید. گزارشگیری دائمی سنگین جای وبهوک را نمیگیرد.
- درخواست و نتیجه فرمان در لاگ ماژول اتصال ثبت میشود؛ برای پشتیبانی operation_id، زمان و نام endpoint کافی است. کلید و OTP را ارسال نکنید.
عیبیابی قدمبهقدم#
| نشانه | چه چیزی را بررسی کنم؟ |
|---|---|
| خطای ۴۰۳ از اولین درخواست | Header key، فعال بودن اتصال، نوع PBX V2، IP مبدأ و محدودیت داخلی را بررسی کنید؛ ابتدا extension را بخوانید. |
| عملیات accepted است ولی مخاطب پاسخ نداده | accepted فقط پذیرش توسط موتور است. رویداد اتصال و CDR را ببینید؛ ممکن است هنوز در حال زنگ باشد. |
extension_not_registered | گوشی داخلی مبدأ را رجیستر کنید و observed_at وضعیت داخلی را ببینید. |
call_not_active / call_not_owned | تماس ممکن است تمام شده یا کانال مربوط به تماس/مرکز دیگری باشد. call_id و leg_id را از همان رویداد زنده بردارید. |
conference_host_required | برای دعوت، leg_id میزبان را بفرستید؛ شناسه عضو عادی کافی نیست. |
| انتقال یا کنفرانس ۲۰۲ میدهد اما عمل نمیکند | result عملیات را بررسی کنید؛ داخلی باید در مکالمه مناسب باشد. وضعیت واقعی را از رویدادهای انتقال/عضویت دنبال کنید. |
| ضبط ۴۰۴ است | مالکیت تماس، آمادهشدن فایل و track درست را بررسی کنید. لینک امضاشده قدیمی را با گرفتن مجدد گزارش تازه کنید. |
| خط انتخابی تماس صوتی کار نمیکند | src باید خط متعلق به مرکز و در مسیر قابل استفاده باشد؛ داخلی مبدأ یا Caller ID دلخواه قابل قبول نیست. |
| HTTP timeout پس از ارسال تماس | با همان درخواست و Idempotency-Key ادامه دهید؛ کلید جدید میتواند تماس دوم ایجاد کند. |
| داشبورد خطای تاریخ دارد | روز پایان نباید آینده باشد؛ فاصله بازه داشبورد حداکثر ۹۰ روز است. |
| گزارش خالی یا در حال تکمیل است | بازه ایران، فیلترها و دسترسی داخلی را بررسی کنید؛ برای نهاییشدن CDR و ضبط زمان در نظر بگیرید. |
