Forem

Cover image for วิธีใช้ Calendly API: คู่มือสำหรับนักพัฒนาเพื่อการผสานรวมการนัดหมาย
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

วิธีใช้ Calendly API: คู่มือสำหรับนักพัฒนาเพื่อการผสานรวมการนัดหมาย

TL;DR

Calendly APIs เหมาะสำหรับสร้างระบบการตั้งเวลาอัตโนมัติในแอปของคุณ รับรองความถูกต้องผ่าน OAuth 2.0 ใช้ api.calendly.com เพื่อเข้าถึงประเภทกิจกรรมและข้อมูลการจอง และอัปเดตแบบเรียลไทม์ด้วยเว็บฮุก หากต้องการทดสอบโดยไม่ต้องสร้างการจองจริง ใช้ Apidog เพื่อตรวจสอบเพย์โหลดเว็บฮุกและทดสอบการเชื่อมต่อ

ทดลองใช้ Apidog วันนี้

บทนำ

Calendly ใช้จัดประชุมหลายล้านครั้งต่อเดือน ทั้งสำหรับสายการขาย เซสชันซัพพอร์ต การปรึกษาหารือ และการสัมภาษณ์ API ของ Calendly ช่วยให้ฝังความสามารถการตั้งเวลาเหล่านี้ลงในแอปของคุณได้โดยตรง

ตัวอย่างการใช้งาน: เมื่อผู้ใช้จองการสาธิต ระบบของคุณ (เช่น CRM) จะได้รับการอัปเดตโดยอัตโนมัติ, การกำหนดเวลาปรึกษาแล้วส่งแบบสอบถาม หรือเมื่อการประชุมถูกยกเลิก จะมีการแจ้งเตือนทีมของคุณ

API ของ Calendly จัดการผ่านเว็บฮุก: เมื่อเกิดเหตุการณ์ (เช่น การจองใหม่, ยกเลิก, หรือเลื่อนเวลา) Calendly จะ POST ไปยัง endpoint ของคุณ จากนั้นคุณสามารถประมวลผลข้อมูลและดำเนินการต่อได้ทันที

💡 หากคุณกำลังสร้างระบบผสานการตั้งเวลา Apidog ช่วยให้ทดสอบเว็บฮุกและตรวจสอบเพย์โหลดได้ง่าย สามารถจำลองการตอบสนองของ Calendly ระหว่างการพัฒนาและตรวจสอบการจัดการ event ทุกประเภทก่อนเชื่อมต่อกับปฏิทินจริง

การรับรองความถูกต้องด้วย OAuth 2.0

Calendly ใช้ OAuth 2.0 สำหรับการเข้าถึง API (ไม่รองรับ API key)

สร้างแอปพลิเคชัน OAuth

  1. ไปที่ Calendly → Integrations → API & Webhooks
  2. คลิก “Create New Application”
  3. กำหนด Redirect URI ของคุณ (เช่น https://yourapp.com/auth/calendly/callback)
  4. รับ 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
Enter fullscreen mode Exit fullscreen mode

2. ผู้ใช้อนุมัติและถูก redirect กลับ

https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
Enter fullscreen mode Exit fullscreen mode

3. แลก Authorization code เป็น 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()
Enter fullscreen mode Exit fullscreen mode

4. ใช้ access token

curl -X GET "https://api.calendly.com/users/me" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

รีเฟรชโทเค็น

Access token หมดอายุใน 2 ชั่วโมง ใช้ refresh 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: 'refresh_token',
    refresh_token: storedRefreshToken
  })
})
Enter fullscreen mode Exit fullscreen mode

การรับข้อมูลผู้ใช้

รับข้อมูลผู้ใช้ปัจจุบัน

curl -X GET "https://api.calendly.com/users/me" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

ตัวอย่าง response:

{
  "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"
  }
}
Enter fullscreen mode Exit fullscreen mode

รับสมาชิกองค์กร

curl -X GET "https://api.calendly.com/organization_memberships/me" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

ประเภทกิจกรรม

ประเภทกิจกรรม (Event Type) คือเทมเพลตการประชุม เช่น โทร 30 นาที, ปรึกษา 60 นาที ฯลฯ

รายการประเภทกิจกรรม

curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

รับประเภทกิจกรรมเฉพาะ

curl -X GET "https://api.calendly.com/event_types/ETC123" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

กิจกรรมที่กำหนดเวลาไว้ (การจอง)

รายการกิจกรรมที่กำหนดเวลาไว้

curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

กรองตามช่วงวันที่:

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"
Enter fullscreen mode Exit fullscreen mode

รับรายละเอียดกิจกรรม

curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

รับผู้เข้าร่วมกิจกรรม

curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

เว็บฮุกสำหรับการอัปเดตแบบเรียลไทม์

เว็บฮุกช่วยให้แอปรับการแจ้งเตือนแบบเรียลไทม์เมื่อมีการจอง เลื่อน หรือยกเลิก

สร้าง Subscription เว็บฮุก

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"
  }'
Enter fullscreen mode Exit fullscreen mode

เหตุการณ์ที่รองรับ:

  • invitee.created (การจองใหม่)
  • invitee.canceled (ยกเลิก)
  • invitee.rescheduled (เลื่อนเวลา)

รายการ Subscription เว็บฮุก

curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

ลบเว็บฮุก

curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
  -H "Authorization: Bearer ACCESS_TOKEN"
Enter fullscreen mode Exit fullscreen mode

การจัดการเพย์โหลดเว็บฮุก

ตรวจสอบลายเซ็นเว็บฮุก

Calendly แนบลายเซ็นไว้ใน header 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')
})
Enter fullscreen mode Exit fullscreen mode

ประมวลผลเหตุการณ์การจอง

function handleWebhook(payload) {
  const { event, payload: data } = payload

  switch (event) {
    case 'invitee.created':
      console.log(`การจองใหม่: ${data.event.start_time}`)
      console.log(`ผู้เข้าร่วม: ${data.email}`)
      // Sync กับ CRM, ส่งอีเมลยืนยัน ฯลฯ
      syncToCRM(data)
      break

    case 'invitee.canceled':
      console.log(`ยกเลิกการจอง: ${data.event.uri}`)
      // อัปเดต CRM, แจ้งทีม ฯลฯ
      removeFromCRM(data)
      break

    case 'invitee.rescheduled':
      console.log(`กำหนดเวลาการจองใหม่: ${data.event.start_time}`)
      // อัปเดตปฏิทิน, แจ้งทีม ฯลฯ
      updateCRM(data)
      break
  }
}
Enter fullscreen mode Exit fullscreen mode

การทดสอบด้วย Apidog

Calendly API ต้องใช้ OAuth ทำให้การทดสอบซับซ้อน Apidog ช่วยให้กระบวนการนี้ง่ายขึ้น

apidog-webhook-test

1. จำลองการตอบสนอง OAuth

ไม่ต้องทำ OAuth flow จริงทุกครั้ง จำลองการตอบสนอง:

{
  "access_token": "mock_access_token",
  "refresh_token": "mock_refresh_token",
  "expires_in": 7200,
  "created_at": 1700000000
}
Enter fullscreen mode Exit fullscreen mode

2. ทดสอบตัวจัดการเว็บฮุก

สร้างเพย์โหลดตัวอย่างสำหรับเว็บฮุก:

{
  "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"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

ส่ง payload นี้ไปยัง endpoint เว็บฮุกของคุณ ตรวจสอบให้แน่ใจว่าระบบรับและประมวลผลได้ถูกต้อง

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
Enter fullscreen mode Exit fullscreen mode

4. ตรวจสอบลายเซ็นเว็บฮุก

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
})
Enter fullscreen mode Exit fullscreen mode

ทดสอบเว็บฮุก Calendly ด้วย Apidog ฟรี

ข้อผิดพลาดทั่วไปและการแก้ไข

401 ไม่ได้รับอนุญาต

สาเหตุ: โทเค็นหมดอายุ/ไม่ถูกต้อง

วิธีแก้ไข:

  1. ตรวจสอบว่า token หมดอายุหรือไม่ (2 ชั่วโมง)
  2. ใช้ refresh token รับ access token ใหม่
  3. หัว Authorization ต้องเป็น Bearer {token}

403 ห้ามเข้าถึง

สาเหตุ: ขอบเขต OAuth ไม่เพียงพอ

วิธีแก้ไข: ตรวจสอบว่าขอบเขตตรงกับที่ต้องใช้เมื่อ authorize

404 ไม่พบ

สาเหตุ: URI ไม่ถูกต้องหรือไม่มีสิทธิ์

วิธีแก้ไข:

  1. ตรวจสอบ URI
  2. ตรวจสอบสิทธิ์ของ user
  3. ตรวจสอบ event type หรือ event id

422 เอนทิตีไม่สามารถประมวลผลได้

สาเหตุ: ข้อมูลใน request ไม่ถูกต้อง

วิธีแก้ไข: ตรวจสอบ response เช่น

{
  "title": "ข้อผิดพลาดในการตรวจสอบความถูกต้อง",
  "message": "พารามิเตอร์ไม่ถูกต้อง: url ต้องเป็น HTTPS URL ที่ถูกต้อง"
}
Enter fullscreen mode Exit fullscreen mode

ทางเลือกและการเปรียบเทียบ

คุณสมบัติ Calendly Acuity Cal.com Calendly
ระดับฟรี จำกัด จำกัด โฮสต์เองฟรี
การเข้าถึง API
เว็บฮุก
OAuth API key API key OAuth
การกำหนดเวลาทีม
โอเพนซอร์ส ไม่ ไม่ ใช่ ไม่

Calendly มีเอกสาร API และ OAuth ที่ยอดเยี่ยม หากต้องการโอเพนซอร์สและใช้งานง่ายกว่า ลองดู Cal.com

กรณีการใช้งานจริง

การผสาน CRM การขาย:

  • ฝัง Calendly ในหน้ากำหนดราคา
  • เมื่อจอง demo:
    1. สร้าง lead ใน Salesforce
    2. แจ้งเตือน Slack ทีมขาย
    3. เพิ่มใน marketing automation
    4. Log กิจกรรมใน customer success platform

แพลตฟอร์มการปรึกษา:

  • ลูกค้าจองคิวทนายผ่าน API
  • ซิงค์การจองกับระบบในองค์กร
  • สร้าง Zoom link
  • ส่งแบบสอบถามล่วงหน้า
  • สร้างไฟล์เคสหลังประชุม

การกำหนดเวลาสัมภาษณ์:

  • ใช้ Calendly จัดการสัมภาษณ์
  • เว็บฮุกอัปเดต ATS
  • แจ้ง hiring manager
  • ส่ง invite ปฏิทิน
  • ติดตามผู้ไม่มาร่วม

สรุป

สิ่งที่ต้องรู้:

  • Calendly ใช้ OAuth 2.0 สำหรับ API
  • เรียกดูประเภทกิจกรรมและจองผ่าน API
  • เว็บฮุกแจ้งเตือนแบบเรียลไทม์
  • ตรวจสอบลายเซ็นเว็บฮุกเสมอ
  • ทดสอบ integration ด้วย Apidog ก่อนเชื่อมต่อจริง

ขั้นตอนถัดไป:

  1. สร้าง OAuth application ใน Calendly
  2. ทำ OAuth flow
  3. ตั้งค่า webhook subscription
  4. ทดสอบเพย์โหลดใน Apidog
  5. นำไปใช้จริง

ทดสอบเว็บฮุก Calendly ด้วย Apidog ฟรี

คำถามที่พบบ่อย

Q: จำเป็นต้องมีแผน Calendly แบบชำระเงินเพื่อใช้ API หรือไม่?

A: ไม่ API ใช้ได้กับทุกแผน (รวมฟรี) แต่แผนฟรีมีข้อจำกัด เว็บฮุกก็ใช้ได้ทุกแผน

Q: เว็บฮุกระดับผู้ใช้ต่างกับองค์กรอย่างไร?

A: ผู้ใช้ = จับ event ของ user เดียว, องค์กร = event ของทีมทั้งหมด ส่วนใหญ่ใช้แบบองค์กร

Q: จะรับ signing key ของเว็บฮุกได้อย่างไร?

A: สร้างเว็บฮุกผ่าน API แล้วดู signing_key ใน response เก็บไว้อย่างปลอดภัย

Q: สร้างการจองผ่าน API ได้หรือไม่?

A: ไม่ได้ ต้องจองผ่าน UI หรือ widget เท่านั้น API เป็น read-only

Q: จัดการ timezone อย่างไร?

A: เวลาทั้งหมดใน API เป็น UTC (ISO 8601) แปลงในแอปตาม timezone user

Q: ขีดจำกัดอัตรา (rate limit) คือเท่าไร?

A: Calendly ไม่แจ้ง rate limit สาธารณะ ใช้ request อย่างเหมาะสม และ retry ด้วย exponential backoff หากถูกจำกัด

Q: รับการจองย้อนหลังได้ไหม?

A: ได้ ใช้ min_start_time และ max_start_time ใน query

Q: ทดสอบ OAuth flow ในเครื่องได้อย่างไร?

A: ใช้ ngrok เปิด endpoint บน localhost แล้วกำหนด redirect URI เป็น ngrok URL ทำ OAuth flow ใน browser และตรวจสอบ callback

Top comments (0)