Hướng Dẫn Lập Trình Viên Sử Dụng Calendly APIs: Tích Hợp Lịch Hẹn

Ashley Innocent

Ashley Innocent

24 tháng 3 2026

Hướng Dẫn Lập Trình Viên Sử Dụng Calendly APIs: Tích Hợp Lịch Hẹn

Apidog cho doanh nghiệp

Triển khai tại chỗ

SSO & RBAC

Tuân thủ SOC 2

Khám phá Apidog Enterprise

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.

💡
Nếu bạn đang xây dựng các tích hợp lên lịch, Apidog giúp bạn kiểm thử các trình xử lý webhook và xác thực payload. Bạn có thể mô phỏng các phản hồi của Calendly trong quá trình phát triển và đảm bảo tích hợp của bạn xử lý tất cả các loại sự kiện trước khi kết nối với lịch thật.
Tải ứng dụ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

  1. Truy cập Calendly → Tích hợp → API & Webhooks
  2. Nhấp vào “Tạo ứng dụng mới”
  3. Đặt URI chuyển hướng của bạn (ví dụ: https://yourapp.com/auth/calendly/callback)
  4. 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:

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:

  1. Kiểm tra token chưa hết hạn (hết hạn sau 2 giờ)
  2. Sử dụng refresh token để lấy access token mới
  3. Đả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:

  1. Access token cần các phạm vi phù hợp.
  2. Khi yêu cầu ủy quyền, hãy bao gồm các phạm vi cần thiết.
  3. 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:

  1. Xác minh URI tài nguyên là chính xác
  2. Đảm bảo người dùng đã xác thực có quyền truy cập vào tài nguyên
  3. 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 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:

  1. Tạo khách hàng tiềm năng trong Salesforce
  2. Gửi thông báo Slack đến nhóm bán hàng
  3. Thêm vào chuỗi tự động hóa tiếp thị
  4. 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:

  1. Đồng bộ hóa đặt lịch với hệ thống lên lịch nội bộ
  2. Tạo liên kết cuộc họp Zoom
  3. Gửi bảng câu hỏi khảo sát 24 giờ trước
  4. 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:

  1. Cập nhật ATS với chi tiết phỏng vấn
  2. Thông báo cho người quản lý tuyển dụng qua email
  3. Gửi lời mời trên lịch cho tất cả những người tham gia
  4. 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:

Các bước tiếp theo của bạn:

  1. Tạo một ứng dụng OAuth trong Calendly
  2. Triển khai luồng OAuth
  3. Thiết lập đăng ký webhook
  4. Kiểm thử với payload giả lập trong Apidog
  5. 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_timemax_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.

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API