ملخص سريع
تتيح لك واجهات برمجة تطبيقات Calendly أتمتة مهام سير العمل الخاصة بالجدولة. يمكنك المصادقة باستخدام OAuth 2.0، والوصول إلى أنواع الأحداث والحجوزات عبر api.calendly.com، وتلقي التحديثات في الوقت الفعلي عبر webhooks. لاختبار التكاملات بسرعة، استخدم Apidog للتحقق من حمولات الـ webhook واختبار تكاملك بدون الحاجة لإنشاء حجوزات حقيقية.
مقدمة
Calendly يعالج ملايين الاجتماعات شهريًا، ويُستخدم لمكالمات المبيعات، جلسات الدعم، الاستشارات، والمقابلات. يمكنك دمج واجهة برمجة التطبيقات مع تطبيقاتك الخاصة لتشغيل إجراءات تلقائية عند كل حجز أو إلغاء أو إعادة جدولة.
السيناريو العملي: عندما يحجز مستخدم عرضًا توضيحيًا، يتم تحديث نظام CRM. بعد جدولة استشارة، يُرسل استبيان. عند إلغاء اجتماع، يُخطر الفريق تلقائيًا.
تعتمد آلية التكامل على webhooks: عند حدوث حدث (إنشاء، إلغاء، إعادة جدولة)، يرسل Calendly طلب POST إلى endpoint تحدده أنت وتعالج الحمولة مباشرة.
💡 إذا كنت تبني تكاملاً للجدولة، استخدم Apidog لاختبار معالجات الـ webhook والتحقق من صحة الحمولات. يمكنك محاكاة استجابات Calendly أثناء التطوير والتأكد من أن تكاملك يدعم جميع أنواع الأحداث قبل الاتصال بالتقويمات الفعلية.
المصادقة باستخدام OAuth 2.0
Calendly لا يدعم مفاتيح API مباشرة. المصادقة تتم عبر OAuth 2.0 فقط.
إنشاء تطبيق OAuth
- توجه إلى Calendly → عمليات التكامل → API وWebhooks
- اختر "إنشاء تطبيق جديد"
- عيّن URI إعادة التوجيه (مثال:
https://yourapp.com/auth/calendly/callback) - احصل على معرّف العميل (Client ID) وسر العميل (Client Secret)
تدفق OAuth
الخطوة 1: إعادة توجيه المستخدم للمصادقة
https://auth.calendly.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
الخطوة 2: المستخدم يصادق ويتم إعادة توجيهه
https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
الخطوة 3: استبدال الكود برمز وصول
const response = await fetch('https://auth.calendly.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64')
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
redirect_uri: 'https://yourapp.com/auth/calendly/callback'
})
})
const { access_token, refresh_token, expires_in } = await response.json()
الخطوة 4: استخدام رمز الوصول
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
رموز التحديث (Refresh tokens)
رموز الوصول تنتهي بعد ساعتين. استخدم رمز التحديث للحصول على رمز جديد:
const response = await fetch('https://auth.calendly.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64')
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: storedRefreshToken
})
})
الحصول على معلومات المستخدم
الحصول على المستخدم الحالي
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
استجابة نموذجية:
{
"resource": {
"avatar_url": "https://calendly.com/avatar.jpg",
"created_at": "2024-01-15T10:00:00Z",
"current_organization": "https://api.calendly.com/organizations/ABC123",
"email": "you@example.com",
"name": "John Doe",
"scheduling_url": "https://calendly.com/johndoe",
"slug": "johndoe",
"timezone": "America/New_York",
"uri": "https://api.calendly.com/users/ABC123"
}
}
الحصول على عضوية المؤسسة
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
أنواع الأحداث
أنواع الأحداث هي قوالب الاجتماعات (مثال: مكالمة 30 دقيقة).
سرد أنواع الأحداث
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
استجابة نموذجية:
{
"resource": {
"uri": "https://api.calendly.com/event_types/ETC123",
"active": true,
"booking_method": "instant",
"color": "#0066FF",
"created_at": "2024-01-15T10:00:00Z",
"description_html": "<p>30-minute consultation</p>",
"duration": 30,
"internal_note": "Use Zoom link",
"kind": "solo",
"name": "30 Min Consultation",
"pooling_type": null,
"profile": {
"name": "John Doe",
"type": "User",
"owner": "https://api.calendly.com/users/ABC123"
},
"scheduling_url": "https://calendly.com/johndoe/30min",
"slug": "30min",
"type": "StandardEventType"
},
"pagination": {
"count": 1,
"next_page": null
}
}
الحصول على نوع حدث معين
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
الأحداث المجدولة (الحجوزات)
الحجوزات هي الأحداث التي ينشئها المستخدمون فعليًا عبر Calendly.
سرد الأحداث المجدولة
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
تصفية حسب النطاق الزمني:
curl -X GET "https://api.calendly.com/scheduled_events?min_start_time=2026-03-01T00:00:00Z&max_start_time=2026-03-31T23:59:59Z" \
-H "Authorization: Bearer ACCESS_TOKEN"
استجابة نموذجية:
{
"resource": {
"uri": "https://api.calendly.com/scheduled_events/ABC123",
"status": "active",
"tracking": {
"utm_campaign": "spring_sale",
"utm_source": "email",
"utm_medium": "newsletter"
},
"created_at": "2026-03-24T10:00:00Z",
"end_time": "2026-03-25T11:00:00Z",
"event_type": "https://api.calendly.com/event_types/ETC123",
"invitees_counter": {
"active": 1,
"limit": 1,
"total": 1
},
"location": {
"type": "zoom",
"join_url": "https://zoom.us/j/123456789"
},
"start_time": "2026-03-25T10:30:00Z",
"updated_at": "2026-03-24T10:00:00Z"
}
}
الحصول على تفاصيل الحدث
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
الحصول على المدعوين لحدث
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
-H "Authorization: Bearer ACCESS_TOKEN"
استجابة نموذجية:
{
"resource": [
{
"cancel_url": "https://calendly.com/cancellations/ABC123",
"created_at": "2026-03-24T10:00:00Z",
"email": "jane@example.com",
"event": "https://api.calendly.com/scheduled_events/ABC123",
"name": "Jane Smith",
"new_invitee": null,
"old_invitee": null,
"reschedule_url": "https://calendly.com/reschedulings/ABC123",
"status": "active",
"text_reminder_number": "+15551234567",
"timezone": "America/New_York",
"tracking": {
"utm_campaign": null,
"utm_source": null
},
"updated_at": "2026-03-24T10:00:00Z",
"uri": "https://api.calendly.com/scheduled_event_invitees/INV123",
"canceled": null
}
]
}
الـ Webhooks للتحديثات في الوقت الفعلي
Webhooks تمكّن تطبيقك من استقبال تحديثات الحجز مباشرة عند حدوثها.
إنشاء اشتراك webhook
curl -X POST "https://api.calendly.com/webhook_subscriptions" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/calendly",
"events": [
"invitee.created",
"invitee.canceled",
"invitee.rescheduled"
],
"organization": "https://api.calendly.com/organizations/ORG123",
"scope": "organization"
}'
الأحداث المتاحة:
-
invitee.created: تم إنشاء حجز جديد -
invitee.canceled: تم إلغاء الحجز -
invitee.rescheduled: تم إعادة جدولة الحجز
سرد اشتراكات الـ webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer ACCESS_TOKEN"
حذف webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
معالجة حمولات الـ webhook
التحقق من توقيعات الـ webhook
Calendly يوقع كل webhook في رأس Calendly-Webhook-Signature. تحقق من صحة التوقيع قبل معالجة الحمولة:
import crypto from 'crypto'
function verifySignature(payload, signature, secret) {
const [t, v1] = signature.split(',')
const timestamp = t.split('=')[1]
const hash = v1.split('=')[1]
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + payload)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(expectedSignature)
)
}
app.post('/webhooks/calendly', (req, res) => {
const signature = req.headers['calendly-webhook-signature']
const payload = JSON.stringify(req.body)
if (!verifySignature(payload, signature, process.env.CALENDLY_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// معالجة الـ webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
معالجة أحداث الحجز
استخدم handler مركزي للتعامل مع أنواع الأحداث:
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`New booking: ${data.event.start_time}`)
console.log(`Invitee: ${data.email}`)
// أضف للـ CRM، أرسل بريد تأكيد ... إلخ
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Booking canceled: ${data.event.uri}`)
// حدث CRM، أخطر الفريق ... إلخ
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Booking rescheduled: ${data.event.start_time}`)
// حدث التقويم، أخطر الفريق ... إلخ
updateCRM(data)
break
}
}
الاختبار باستخدام Apidog
اختبار تكامل Calendly يتطلب OAuth، مما يزيد من تعقيد التجربة. Apidog يبسط العملية.
1. محاكاة استجابات OAuth
أثناء التطوير، استخدم بيانات رموز وهمية بدلًا من تدفق OAuth الكامل:
{
"access_token": "mock_access_token",
"refresh_token": "mock_refresh_token",
"expires_in": 7200,
"created_at": 1700000000
}
2. اختبار معالجات الـ webhook
أنشئ payloads وهمية لإرسالها إلى endpoint الخاص بك:
{
"created_at": "2026-03-24T10:00:00Z",
"event": "invitee.created",
"payload": {
"email": "test@example.com",
"name": "Test User",
"event": {
"start_time": "2026-03-25T10:30:00Z",
"end_time": "2026-03-25T11:00:00Z",
"event_type": {
"name": "30 Min Consultation"
}
}
}
}
أرسل الحمولة إلى نقطة النهاية وتحقق من المعالجة.
3. متغيرات البيئة
استخدم متغيرات البيئة التالية لتسهيل الاختبار:
CALENDLY_CLIENT_ID: abc123
CALENDLY_CLIENT_SECRET: xyz789
CALENDLY_ACCESS_TOKEN: stored_token
CALENDLY_REFRESH_TOKEN: stored_refresh
CALENDLY_WEBHOOK_SECRET: webhook_signing_secret
4. التحقق من توقيعات الـ webhook
أضف اختبار تحقق من التوقيع في Apidog أو عبر Postman:
pm.test('Webhook signature is valid', () => {
const signature = pm.request.headers.get('Calendly-Webhook-Signature')
pm.expect(signature).to.exist
const payload = pm.request.body.raw
const secret = pm.environment.get('CALENDLY_WEBHOOK_SECRET')
// Verify signature
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
اختبر webhooks Calendly باستخدام Apidog — مجانًا.
الأخطاء الشائعة والإصلاحات
401 غير مصرح به (Unauthorized)
السبب: رمز وصول غير صالح أو منتهي الصلاحية.
الإصلاح:
- تحقق من صلاحية رمز الوصول (تنتهي بعد ساعتين)
- استخدم refresh token لتجديد الرمز
- تأكد أن رأس Authorization بصيغة
Bearer {token}
403 ممنوع (Forbidden)
السبب: نطاق OAuth غير كافٍ.
الإصلاح: عند طلب المصادقة، أضف النطاقات المطلوبة. نطاقات Calendly تُحدد حسب ما يصرح به المستخدم.
404 غير موجود (Not Found)
السبب: المورد غير موجود أو لا يملك المستخدم صلاحية الوصول.
الإصلاح:
- تحقق من URI المورد
- تأكد أن المستخدم المصادق لديه صلاحية الوصول
- تحقق من صلاحية معرف الحدث أو نوع الحدث
422 كيان غير قابل للمعالجة (Unprocessable Entity)
السبب: خطأ في التحقق من الطلب.
الإصلاح: تحقق من تفاصيل الاستجابة:
{
"title": "Validation Error",
"message": "Invalid parameter: url must be a valid HTTPS URL"
}
البدائل والمقارنات
| الميزة | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| الخطة المجانية | محدود | محدود | مُستضاف ذاتيًا مجانًا | ✓ |
| الوصول إلى API | ✓ | ✓ | ✓ | ✓ |
| Webhooks | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | مفتاح API | مفتاح API | OAuth |
| جدولة الفريق | ✓ | ✓ | ✓ | ✓ |
| مفتوح المصدر | لا | لا | نعم | لا |
يقدّم Calendly أفضل توثيق لـ API وتدفق OAuth. إذا كنت تبحث عن بديل مفتوح المصدر بآلية أبسط، جرّب Cal.com.
حالات استخدام واقعية
تكامل CRM للمبيعات:
شركة SaaS تدمج Calendly في صفحة التسعير. عند حجز demo، يُطلق webhook:
- إنشاء lead في Salesforce
- إرسال إشعار Slack للمبيعات
- إضافة المستخدم إلى تسلسل تسويق
- تسجيل النشاط في منصة نجاح العملاء
منصة استشارية:
منصة خدمات قانونية تتيح العملاء حجز استشارات. التكامل يشمل:
- مزامنة الحجوزات مع النظام الداخلي
- إنشاء روابط Zoom
- إرسال استبيان قبول قبل 24 ساعة
- إنشاء ملف حالة بعد الاجتماع
جدولة المقابلات:
منصة توظيف تستخدم Calendly لمقابلات المرشحين. الـ webhooks:
- تحديث نظام تتبع المتقدمين (ATS)
- إخطار مدير التوظيف
- إرسال دعوات تقويم
- تتبع حالات عدم الحضور
الخاتمة
تلخيص عملي:
- Calendly يستخدم OAuth 2.0 لمصادقة الـ API.
- يمكنك الوصول لأنواع الأحداث والحجوزات عبر الـ API.
- Webhooks توفر إشعارات حجز في الوقت الفعلي.
- تحقق دائمًا من توقيعات الـ webhook.
- اختبر تكاملك باستخدام Apidog قبل ربطه بالتقويمات الحقيقية.
خطوات التنفيذ:
- أنشئ تطبيق OAuth في Calendly
- نفّذ تدفق OAuth في تطبيقك
- أضف اشتراك webhook
- اختبر باستخدام حمولات وهمية في Apidog
- انشر التكامل في الإنتاج
اختبر webhooks Calendly باستخدام Apidog — مجانًا.
الأسئلة الشائعة
هل أحتاج إلى خطة Calendly مدفوعة لاستخدام الـ API؟
لا، الـ API متاح لجميع الخطط بما في ذلك المجانية. لكن الميزات محدودة في الخطة المجانية. Webhooks متوفرة للجميع.
ما الفرق بين webhooks على مستوى المستخدم والمؤسسة؟
Webhooks المستخدم تلتقط أحداث مستخدم واحد فقط. Webhooks المؤسسة تلتقط الأحداث لكل أعضاء الفريق. الأغلب يختار نطاق المؤسسة.
كيف أحصل على مفتاح توقيع الـ webhook السري؟
عند إنشاء webhook عبر الـ API، ستجد signing_key في الاستجابة. احفظه بشكل آمن للتحقق من التوقيعات.
هل يمكنني إنشاء الحجوزات عبر الـ API؟
لا. لا يوجد endpoint لإنشاء حجوزات. جميع الحجوزات تتم عبر واجهة مستخدم Calendly أو الأدوات المدمجة. الـ API للقراءة فقط.
كيف أتعامل مع المناطق الزمنية؟
جميع الطوابع الزمنية بصيغة UTC (ISO 8601). حوّل التوقيت محليًا في تطبيقك. منطقة المستخدم الزمنية متاحة في بيانات المستخدم.
ما هو حد المعدل (rate limit)؟
لم يتم توثيقها علنًا. استخدم أنماط طلب معتدلة. إذا واجهت حدودًا، طبّق تراجع أُسّي.
هل يمكنني الحصول على الحجوزات التاريخية؟
نعم، استخدم min_start_time وmax_start_time للاستعلام عن الأحداث القديمة.
كيف أختبر تدفق OAuth محليًا؟
استخدم خدمة مثل ngrok لتعريض endpoint محلي للعامة. اضبط URI إعادة التوجيه على عنوان ngrok وأكمل التدفق في المتصفح.

Top comments (0)