TÓM TẮT
API của Calendly cho phép bạn tự động hóa các quy trình lên lịch. Bạn xác thực bằng OAuth 2.0, truy cập các loại sự kiện và đặt lịch qua api.calendly.com, và nhận cập nhật thời gian thực qua webhooks. Để kiểm thử, hãy sử dụng Apidog để xác thực payload webhook và kiểm tra tích hợp của bạn mà không cần tạo các đặt lịch thật.
Giới thiệu
Calendly xử lý hàng triệu cuộc họp mỗi tháng. Mọi người sử dụng nó cho các cuộc gọi bán hàng, buổi hỗ trợ, tư vấn và phỏng vấn. API cho phép bạn nhúng khả năng lên lịch đó vào các ứng dụng của riêng mình.
Mô hình phổ biến: bạn muốn các đặt lịch của Calendly kích hoạt hành động trong hệ thống của mình. Người dùng đặt lịch demo, và CRM của bạn được cập nhật. Một buổi tư vấn được lên lịch, và bạn gửi một bảng câu hỏi. Một cuộc họp bị hủy, và bạn thông báo cho nhóm của mình.
API của Calendly xử lý việc này thông qua webhooks. Khi các sự kiện xảy ra (đặt lịch được tạo, bị hủy, được lên lịch lại), Calendly sẽ POST đến các endpoint của bạn. Bạn xử lý payload và thực hiện hành động.
Xác thực với OAuth 2.0
Calendly sử dụng OAuth 2.0 để truy cập API. Bạn không thể chỉ sử dụng khóa API.
Tạo ứng dụng OAuth
- Truy cập Calendly → Tích hợp → API & Webhooks
- Nhấp vào “Tạo ứng dụng mới”
- Đặt URI chuyển hướng của bạn (ví dụ:
https://yourapp.com/auth/calendly/callback) - Lấy client ID và client secret của bạn
Luồng OAuth
Bước 1: Chuyển hướng người dùng để ủy quyền
https://auth.calendly.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
Bước 2: Người dùng ủy quyền và được chuyển hướng trở lại
https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
Bước 3: Đổi mã để lấy access token
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()
Bước 4: Sử dụng token
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Refresh token
Access token hết hạn sau 2 giờ. Sử dụng refresh token để lấy token mới:
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
})
})
Lấy thông tin người dùng
Lấy người dùng hiện tại
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Phản hồi:
{
"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"
}
}
Lấy tư cách thành viên tổ chức
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Loại sự kiện
Loại sự kiện là các mẫu cuộc họp mà người dùng tạo (cuộc gọi 30 phút, tư vấn 60 phút, v.v.).
Liệt kê các loại sự kiện
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Phản hồi:
{
"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
}
}
Lấy một loại sự kiện cụ thể
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Sự kiện đã lên lịch (đặt lịch)
Sự kiện là các đặt lịch thực tế được thực hiện thông qua Calendly.
Liệt kê các sự kiện đã lên lịch
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Lọc theo khoảng thời gian:
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"
Phản hồi:
{
"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"
}
}
Lấy chi tiết sự kiện
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Lấy người được mời cho một sự kiện
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
-H "Authorization: Bearer ACCESS_TOKEN"
Phản hồi:
{
"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 để cập nhật thời gian thực
Webhooks thông báo cho ứng dụng của bạn về các sự kiện đặt lịch theo thời gian thực.
Tạo đăng ký 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"
}'
Các sự kiện có sẵn:
invitee.created- Đặt lịch mới được tạoinvitee.canceled- Đặt lịch bị hủyinvitee.rescheduled- Đặt lịch được lên lịch lại
Liệt kê các đăng ký webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Xóa một webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Xử lý payload webhook
Xác minh chữ ký webhook
Calendly ký webhooks bằng một chữ ký trong tiêu đề 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')
}
// Xử lý webhook
handleWebhook(req.body)
res.status(200).send('OK')
})
Xử lý các sự kiện đặt lịch
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`Đặt lịch mới: ${data.event.start_time}`)
console.log(`Người được mời: ${data.email}`)
// Thêm vào CRM, gửi email xác nhận, v.v.
syncToCRM(data)
break
case 'invitee.canceled':
console.log(`Đặt lịch bị hủy: ${data.event.uri}`)
// Cập nhật CRM, thông báo cho nhóm, v.v.
removeFromCRM(data)
break
case 'invitee.rescheduled':
console.log(`Đặt lịch được lên lịch lại: ${data.event.start_time}`)
// Cập nhật lịch, thông báo cho nhóm, v.v.
updateCRM(data)
break
}
}
Kiểm thử với Apidog
API của Calendly yêu cầu OAuth, điều này làm phức tạp việc kiểm thử. Apidog đơn giản hóa điều này.

1. Mô phỏng phản hồi OAuth
Trong quá trình phát triển, không cần thực hiện toàn bộ luồng OAuth mỗi lần. Mô phỏng phản hồi token:
{
"access_token": "mock_access_token",
"refresh_token": "mock_refresh_token",
"expires_in": 7200,
"created_at": 1700000000
}
2. Kiểm thử trình xử lý webhook
Tạo payload webhook giả lập:
{
"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"
}
}
}
}
Gửi đến endpoint webhook của bạn và xác minh việc xử lý.
3. Biến môi trường
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. Xác thực chữ ký 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')
// Xác minh chữ ký
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
Kiểm thử webhook của Calendly với Apidog - miễn phí
Các lỗi phổ biến và cách khắc phục
401 Không được ủy quyền
Nguyên nhân: Token không hợp lệ hoặc đã hết hạn.
Khắc phục:
- Kiểm tra token chưa hết hạn (hết hạn sau 2 giờ)
- Sử dụng refresh token để lấy access token mới
- Đảm bảo tiêu đề Authorization là
Bearer {token}
403 Bị cấm
Nguyên nhân: Phạm vi OAuth không đủ.
Khắc phục:
- Access token cần các phạm vi phù hợp.
- Khi yêu cầu ủy quyền, hãy bao gồm các phạm vi cần thiết.
- Các phạm vi của Calendly là ngầm định dựa trên những gì người dùng ủy quyền.
404 Không tìm thấy
Nguyên nhân: Tài nguyên không tồn tại hoặc người dùng không có quyền truy cập.
Khắc phục:
- Xác minh URI tài nguyên là chính xác
- Đảm bảo người dùng đã xác thực có quyền truy cập vào tài nguyên
- Kiểm tra loại sự kiện hoặc ID sự kiện hợp lệ
422 Thực thể không thể xử lý
Nguyên nhân: Lỗi xác thực trong yêu cầu.
Khắc phục: Kiểm tra phản hồi để biết chi tiết:
{
"title": "Lỗi xác thực",
"message": "Tham số không hợp lệ: url phải là một URL HTTPS hợp lệ"
}
Các lựa chọn thay thế và so sánh
| Tính năng | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| Gói miễn phí | Hạn chế | Hạn chế | Miễn phí tự lưu trữ | ✓ |
| Truy cập API | ✓ | ✓ | ✓ | ✓ |
| Webhooks | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | Khóa API | Khóa API | OAuth |
| Lên lịch nhóm | ✓ | ✓ | ✓ | ✓ |
| Mã nguồn mở | Không | Không | Có | Không |
Calendly có tài liệu API và luồng OAuth được hoàn thiện nhất. Cal.com là lựa chọn thay thế mã nguồn mở với xác thực bằng khóa API đơn giản hơn.
Các trường hợp sử dụng thực tế
Tích hợp CRM bán hàng. Một công ty SaaS B2B nhúng Calendly vào trang giá của họ. Khi ai đó đặt lịch demo, webhook kích hoạt:
- Tạo khách hàng tiềm năng trong Salesforce
- Gửi thông báo Slack đến nhóm bán hàng
- Thêm vào chuỗi tự động hóa tiếp thị
- Ghi lại hoạt động trong nền tảng chăm sóc khách hàng
Nền tảng tư vấn. Một nền tảng dịch vụ pháp lý cho phép khách hàng đặt lịch tư vấn với luật sư. Tích hợp API:
- Đồng bộ hóa đặt lịch với hệ thống lên lịch nội bộ
- Tạo liên kết cuộc họp Zoom
- Gửi bảng câu hỏi khảo sát 24 giờ trước
- Tạo hồ sơ vụ việc khi cuộc họp hoàn tất
Lên lịch phỏng vấn. Một nền tảng tuyển dụng sử dụng Calendly cho các cuộc phỏng vấn ứng viên. Webhooks:
- Cập nhật ATS với chi tiết phỏng vấn
- Thông báo cho người quản lý tuyển dụng qua email
- Gửi lời mời trên lịch cho tất cả những người tham gia
- Theo dõi những người vắng mặt để theo dõi
Kết luận
Dưới đây là những gì bạn đã học:
- Calendly sử dụng OAuth 2.0 để xác thực API
- Truy cập các loại sự kiện và sự kiện đã lên lịch thông qua API
- Webhooks cung cấp thông báo đặt lịch theo thời gian thực
- Luôn xác minh chữ ký webhook để đảm bảo bảo mật
- Kiểm thử với Apidog trước khi kết nối với lịch thật
Các bước tiếp theo của bạn:
- Tạo một ứng dụng OAuth trong Calendly
- Triển khai luồng OAuth
- Thiết lập đăng ký webhook
- Kiểm thử với payload giả lập trong Apidog
- Triển khai lên môi trường sản xuất
Kiểm thử webhook của Calendly với Apidog - miễn phí
Câu hỏi thường gặp
Tôi có cần gói trả phí của Calendly để sử dụng API không?Không. API có sẵn trên tất cả các gói bao gồm cả gói miễn phí. Tuy nhiên, các gói miễn phí có các tính năng hạn chế. Webhooks có sẵn trên tất cả các gói.
Sự khác biệt giữa webhook cấp người dùng và cấp tổ chức là gì?Webhook cấp người dùng chỉ ghi lại các sự kiện cho một người dùng. Webhook cấp tổ chức ghi lại các sự kiện cho tất cả các thành viên trong nhóm. Hầu hết các tích hợp sử dụng phạm vi tổ chức.
Làm cách nào để lấy secret ký webhook?Khi bạn tạo webhook qua API, phản hồi sẽ bao gồm một signing_key. Lưu trữ cái này một cách an toàn. Nó được sử dụng để xác minh chữ ký webhook.
Tôi có thể tạo đặt lịch qua API không?Không. Calendly không có endpoint API để tạo đặt lịch. Các đặt lịch phải được thực hiện thông qua giao diện người dùng của Calendly hoặc các widget nhúng. API chỉ có quyền đọc đối với các đặt lịch.
Tôi xử lý chuyển đổi múi giờ như thế nào?Tất cả các dấu thời gian trong API đều là UTC (ISO 8601). Chuyển đổi sang giờ địa phương trong ứng dụng của bạn. Múi giờ của người dùng có sẵn trong tài nguyên người dùng.
Giới hạn tốc độ là gì?Calendly không công bố công khai giới hạn tốc độ. Sử dụng các mẫu yêu cầu hợp lý. Nếu bạn gặp giới hạn, hãy triển khai exponential backoff.
Tôi có thể lấy các đặt lịch trong quá khứ không?Có. Sử dụng min_start_time và max_start_time để truy vấn các sự kiện trong quá khứ. Không có giới hạn về khoảng thời gian bạn có thể truy vấn.
Làm cách nào để kiểm thử luồng OAuth cục bộ?Sử dụng một dịch vụ tunneling như ngrok để hiển thị máy chủ cục bộ của bạn. Đặt URI chuyển hướng thành URL ngrok của bạn. Hoàn tất luồng OAuth trong trình duyệt, sau đó kiểm tra callback.
