Intinya
API Calendly memungkinkan Anda mengotomatiskan alur kerja penjadwalan. Anda melakukan autentikasi dengan OAuth 2.0, mengakses tipe acara dan pemesanan melalui api.calendly.com, dan menerima pembaruan real-time melalui webhook. Untuk pengujian, gunakan Apidog untuk memvalidasi payload webhook dan menguji integrasi Anda tanpa membuat pemesanan nyata.
Pendahuluan
Calendly memproses jutaan pertemuan setiap bulannya. Orang-orang menggunakannya untuk panggilan penjualan, sesi dukungan, konsultasi, dan wawancara. API memungkinkan Anda menyematkan kekuatan penjadwalan tersebut ke dalam aplikasi Anda sendiri.
Pola umumnya: Anda ingin pemesanan Calendly memicu tindakan di sistem Anda. Seorang pengguna memesan demo, dan CRM Anda diperbarui. Sebuah konsultasi dijadwalkan, dan Anda mengirimkan kuesioner. Sebuah pertemuan dibatalkan, dan Anda memberi tahu tim Anda.
API Calendly menangani ini melalui webhook. Ketika acara terjadi (pemesanan dibuat, dibatalkan, dijadwal ulang), Calendly mengirimkan POST ke endpoint Anda. Anda memproses payload dan mengambil tindakan.
Autentikasi dengan OAuth 2.0
Calendly menggunakan OAuth 2.0 untuk akses API. Anda tidak bisa hanya menggunakan kunci API.
Buat aplikasi OAuth
- Buka Calendly → Integrasi → API & Webhook
- Klik “Buat Aplikasi Baru”
- Atur URI pengalihan Anda (misalnya,
https://yourapp.com/auth/calendly/callback) - Dapatkan ID klien dan rahasia klien Anda
Alur OAuth
Langkah 1: Arahkan pengguna untuk otorisasi
https://auth.calendly.com/oauth/authorize?
client_id=YOUR_CLIENT_ID&
response_type=code&
redirect_uri=https://yourapp.com/auth/calendly/callback
Langkah 2: Pengguna mengotorisasi dan diarahkan kembali
https://yourapp.com/auth/calendly/callback?code=AUTHORIZATION_CODE
Langkah 3: Tukar kode untuk token akses
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()
Langkah 4: Gunakan token
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Token penyegaran
Token akses kedaluwarsa setelah 2 jam. Gunakan token penyegaran untuk mendapatkan yang baru:
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
})
})
Mendapatkan informasi pengguna
Dapatkan pengguna saat ini
curl -X GET "https://api.calendly.com/users/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respons:
{
"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"
}
}
Dapatkan keanggotaan organisasi
curl -X GET "https://api.calendly.com/organization_memberships/me" \
-H "Authorization: Bearer ACCESS_TOKEN"
Tipe acara
Tipe acara adalah templat pertemuan yang dibuat pengguna (panggilan 30 menit, konsultasi 60 menit, dll.).
Daftar tipe acara
curl -X GET "https://api.calendly.com/event_types?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respons:
{
"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
}
}
Dapatkan tipe acara tertentu
curl -X GET "https://api.calendly.com/event_types/ETC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Acara terjadwal (pemesanan)
Acara adalah pemesanan aktual yang dibuat melalui Calendly.
Daftar acara terjadwal
curl -X GET "https://api.calendly.com/scheduled_events?user=https://api.calendly.com/users/ABC123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Filter berdasarkan rentang tanggal:
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"
Respons:
{
"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"
}
}
Dapatkan detail acara
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Dapatkan peserta untuk suatu acara
curl -X GET "https://api.calendly.com/scheduled_events/EVENT_ID/invitees" \
-H "Authorization: Bearer ACCESS_TOKEN"
Respons:
{
"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
}
]
}
Webhook untuk pembaruan real-time
Webhook memberi tahu aplikasi Anda tentang acara pemesanan secara real time.
Buat langganan 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"
}'
Acara yang tersedia:
invitee.created- Pemesanan baru dibuatinvitee.canceled- Pemesanan dibatalkaninvitee.rescheduled- Pemesanan dijadwal ulang
Daftar langganan webhook
curl -X GET "https://api.calendly.com/webhook_subscriptions?organization=https://api.calendly.com/organizations/ORG123" \
-H "Authorization: Bearer ACCESS_TOKEN"
Hapus webhook
curl -X DELETE "https://api.calendly.com/webhook_subscriptions/WEBHOOK_ID" \
-H "Authorization: Bearer ACCESS_TOKEN"
Menangani payload webhook
Verifikasi tanda tangan webhook
Calendly menandatangani webhook dengan tanda tangan di 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')
})
Proses acara pemesanan
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
}
}
Pengujian dengan Apidog
API Calendly memerlukan OAuth, yang mempersulit pengujian. Apidog menyederhanakan hal ini.

1. Mock respons OAuth
Selama pengembangan, jangan melalui alur OAuth penuh setiap saat. Tirukan respons token:
{
"access_token": "mock_access_token",
"refresh_token": "mock_refresh_token",
"expires_in": 7200,
"created_at": 1700000000
}
2. Uji penangan webhook
Buat payload webhook tiruan:
{
"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"
}
}
}
}
Kirim ke endpoint webhook Anda dan verifikasi penanganannya.
3. Variabel lingkungan
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. Validasi tanda tangan 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
})
Uji webhook Calendly dengan Apidog - gratis
Kesalahan umum dan perbaikan
401 Tidak Sah
Penyebab: Token tidak valid atau kedaluwarsa.
Perbaikan:
- Periksa token belum kedaluwarsa (kedaluwarsa 2 jam)
- Gunakan token penyegaran untuk mendapatkan token akses baru
- Pastikan header Otorisasi adalah
Bearer {token}
403 Terlarang
Penyebab: Lingkup OAuth tidak cukup.
Perbaikan: Token OAuth memerlukan lingkup yang sesuai. Saat meminta otorisasi, sertakan lingkup yang dibutuhkan. Lingkup Calendly bersifat implisit berdasarkan apa yang diotorisasi pengguna.
404 Tidak Ditemukan
Penyebab: Sumber daya tidak ada atau pengguna tidak memiliki akses.
Perbaikan:
- Verifikasi URI sumber daya sudah benar
- Pastikan pengguna yang diautentikasi memiliki akses ke sumber daya tersebut
- Periksa apakah tipe acara atau ID acara valid
422 Entitas Tidak Dapat Diproses
Penyebab: Kesalahan validasi dalam permintaan.
Perbaikan: Periksa respons untuk detailnya:
{
"title": "Validation Error",
"message": "Invalid parameter: url must be a valid HTTPS URL"
}
Alternatif dan perbandingan
| Fitur | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| Paket gratis | Terbatas | Terbatas | Gratis mandiri | ✓ |
| Akses API | ✓ | ✓ | ✓ | ✓ |
| Webhook | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | Kunci API | Kunci API | OAuth |
| Penjadwalan tim | ✓ | ✓ | ✓ | ✓ |
| Sumber terbuka | Tidak | Tidak | Ya | Tidak |
Calendly memiliki dokumentasi API dan alur OAuth yang paling rapi. Cal.com adalah alternatif sumber terbuka dengan autentikasi kunci API yang lebih sederhana.
Kasus penggunaan dunia nyata
Integrasi CRM Penjualan. Sebuah perusahaan B2B SaaS menyematkan Calendly di halaman harga mereka. Ketika seseorang memesan demo, webhook memicu:
- Membuat prospek di Salesforce
- Mengirim notifikasi Slack ke tim penjualan
- Menambahkan ke urutan otomatisasi pemasaran
- Mencatat aktivitas di platform sukses pelanggan
Platform konsultasi. Platform layanan hukum memungkinkan klien memesan konsultasi dengan pengacara. Integrasi API:
- Menyinkronkan pemesanan ke sistem penjadwalan internal
- Menghasilkan tautan pertemuan Zoom
- Mengirim kuesioner awal 24 jam sebelumnya
- Membuat berkas kasus saat pertemuan selesai
Penjadwalan wawancara. Platform rekrutmen menggunakan Calendly untuk wawancara kandidat. Webhook:
- Memperbarui ATS dengan detail wawancara
- Memberi tahu manajer perekrutan melalui email
- Mengirim undangan kalender ke semua peserta
- Melacak ketidakhadiran untuk tindak lanjut
Kesimpulan
Inilah yang telah Anda pelajari:
- Calendly menggunakan OAuth 2.0 untuk autentikasi API
- Akses tipe acara dan acara terjadwal melalui API
- Webhook menyediakan notifikasi pemesanan real-time
- Selalu verifikasi tanda tangan webhook untuk keamanan
- Uji dengan Apidog sebelum terhubung ke kalender nyata
Langkah Anda selanjutnya:
- Buat aplikasi OAuth di Calendly
- Implementasikan alur OAuth
- Siapkan langganan webhook
- Uji dengan payload tiruan di Apidog
- Deploy ke produksi
Uji webhook Calendly dengan Apidog - gratis
FAQ
Apakah saya memerlukan paket Calendly berbayar untuk menggunakan API?Tidak. API tersedia di semua paket termasuk yang gratis. Namun, paket gratis memiliki fitur terbatas. Webhook tersedia di semua paket.
Apa perbedaan antara webhook tingkat pengguna dan tingkat organisasi?Webhook tingkat pengguna hanya menangkap acara untuk satu pengguna. Webhook tingkat organisasi menangkap acara untuk semua anggota tim. Sebagian besar integrasi menggunakan lingkup organisasi.
Bagaimana cara mendapatkan rahasia penandatanganan webhook?Saat Anda membuat webhook melalui API, responsnya menyertakan signing_key. Simpan ini dengan aman. Ini digunakan untuk memverifikasi tanda tangan webhook.
Dapatkah saya membuat pemesanan melalui API?Tidak. Calendly tidak memiliki endpoint API untuk membuat pemesanan. Pemesanan harus terjadi melalui UI Calendly atau widget tersemat. API bersifat baca-saja untuk pemesanan.
Bagaimana cara menangani konversi zona waktu?Semua stempel waktu di API adalah UTC (ISO 8601). Konversikan ke waktu lokal di aplikasi Anda. Zona waktu pengguna tersedia di sumber daya pengguna.
Berapa batas laju (rate limit)?Calendly tidak mendokumentasikan batas laju secara publik. Gunakan pola permintaan yang wajar. Jika Anda mencapai batas, terapkan backoff eksponensial.
Bisakah saya mendapatkan pemesanan historis?Ya. Gunakan min_start_time dan max_start_time untuk menanyakan acara historis. Tidak ada batasan seberapa jauh ke belakang Anda dapat menanyakan.
Bagaimana cara menguji alur OAuth secara lokal?Gunakan layanan tunneling seperti ngrok untuk mengekspos server lokal Anda. Atur URI pengalihan ke URL ngrok Anda. Selesaikan alur OAuth di browser, lalu periksa callbacknya.
