ملخص سريع
تتيح لك واجهات برمجة تطبيقات Calendly أتمتة مهام سير عمل الجدولة. يمكنك المصادقة باستخدام OAuth 2.0، والوصول إلى أنواع الأحداث والحجوزات عبر api.calendly.com، وتلقي التحديثات في الوقت الفعلي عبر الـ webhooks. للاختبار، استخدم Apidog للتحقق من حمولات الـ webhook واختبار تكاملك دون إنشاء حجوزات حقيقية.
مقدمة
يعالج Calendly ملايين الاجتماعات شهريًا. يستخدمه الناس لمكالمات المبيعات، وجلسات الدعم، والاستشارات، والمقابلات. تتيح لك واجهة برمجة التطبيقات دمج قوة الجدولة هذه في تطبيقاتك الخاصة.
النمط الشائع: تريد أن تؤدي حجوزات Calendly إلى تشغيل إجراءات في نظامك. يحجز مستخدم عرضًا توضيحيًا، ويتم تحديث نظام إدارة علاقات العملاء (CRM) الخاص بك. يتم جدولة استشارة، وترسل استبيانًا. يتم إلغاء اجتماع، وتقوم بإخطار فريقك.
تتعامل واجهة برمجة تطبيقات Calendly مع هذا عبر الـ webhooks. عندما تحدث أحداث (إنشاء حجز، إلغاء، إعادة جدولة)، يرسل Calendly طلبات POST إلى نقاط النهاية الخاصة بك. تقوم بمعالجة الحمولة واتخاذ الإجراء.
المصادقة باستخدام OAuth 2.0
يستخدم Calendly OAuth 2.0 للوصول إلى واجهة برمجة التطبيقات. لا يمكنك مجرد استخدام مفتاح API.
إنشاء تطبيق OAuth
- اذهب إلى Calendly ← عمليات التكامل ← API و Webhooks
- انقر على "إنشاء تطبيق جديد"
- عيّن URI إعادة التوجيه الخاص بك (على سبيل المثال،
https://yourapp.com/auth/calendly/callback) - احصل على معرّف العميل وسر العميل الخاص بك
تدفق 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 دقيقة، استشارة لمدة 60 دقيقة، إلخ).
سرد أنواع الأحداث
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 على الـ webhooks بتوقيع في رأس 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')
}
// Process webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
معالجة أحداث الحجز
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}`)
// Add to CRM, send confirmation email, etc.
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Booking canceled: ${data.event.uri}`)
// Update CRM, notify team, etc.
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Booking rescheduled: ${data.event.start_time}`)
// Update calendar, notify team, etc.
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
أنشئ حمولات webhook وهمية:
{
"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"
}
}
}
}
أرسل إلى نقطة نهاية الـ webhook الخاصة بك وتحقق من المعالجة.
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
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 header) هو
Bearer {token}
403 ممنوع (Forbidden)
السبب: نطاق OAuth غير كافٍ.
الإصلاح: يحتاج رمز 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 أفضل توثيق لواجهة برمجة التطبيقات وتدفق OAuth. يعد Cal.com البديل مفتوح المصدر بمصادقة مفتاح API أبسط.
حالات استخدام واقعية
تكامل نظام إدارة علاقات العملاء (CRM) للمبيعات. تقوم شركة برمجيات كخدمة (SaaS) تعمل بنظام B2B بدمج Calendly في صفحة التسعير الخاصة بها. عندما يحجز شخص ما عرضًا توضيحيًا، يقوم الـ webhook بتشغيل ما يلي:
- إنشاء عميل محتمل في 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 على مستوى المستخدم الأحداث لمستخدم واحد فقط. تلتقط webhooks على مستوى المؤسسة الأحداث لجميع أعضاء الفريق. تستخدم معظم عمليات التكامل نطاق المؤسسة.
كيف أحصل على مفتاح توقيع webhook السري؟عندما تنشئ webhook عبر API، تتضمن الاستجابة signing_key. قم بتخزينه بشكل آمن. يتم استخدامه للتحقق من توقيعات الـ webhook.
هل يمكنني إنشاء حجوزات عبر API؟لا. لا يوجد لدى Calendly نقطة نهاية API لإنشاء الحجوزات. يجب أن تتم الحجوزات من خلال واجهة مستخدم Calendly أو الأدوات المدمجة. API للقراءة فقط للحجوزات.
كيف أتعامل مع تحويلات المنطقة الزمنية؟جميع الطوابع الزمنية في API هي بالتوقيت العالمي المنسق (UTC) (ISO 8601). قم بالتحويل إلى التوقيت المحلي في تطبيقك. المنطقة الزمنية للمستخدم متاحة في مورد المستخدم.
ما هو حد المعدل (rate limit)؟لا يقوم Calendly بتوثيق حدود المعدل علنًا. استخدم أنماط طلب معقولة. إذا وصلت إلى الحدود، قم بتنفيذ تراجع أُسّي.
هل يمكنني الحصول على الحجوزات التاريخية؟نعم. استخدم min_start_time و max_start_time للاستعلام عن الأحداث التاريخية. لا يوجد حد للمدة التي يمكنك الاستعلام عنها.
كيف أختبر تدفق OAuth محليًا؟استخدم خدمة نفق مثل ngrok لعرض خادمك المحلي. اضبط URI إعادة التوجيه على عنوان URL الخاص بـ ngrok. أكمل تدفق OAuth في المتصفح، ثم افحص رد الاتصال.
