要約
Calendly APIを使用すると、スケジューリングワークフローを自動化できます。OAuth 2.0で認証し、api.calendly.com経由でイベントタイプと予約にアクセスし、Webhook経由でリアルタイムの更新を受け取ります。テストには、Apidogを使用してWebhookペイロードを検証し、実際の予約を作成せずにインテグレーションをテストできます。
はじめに
Calendlyは毎月何百万もの会議を処理しています。人々はこれを営業電話、サポートセッション、コンサルテーション、面接などに利用しています。APIを使用すると、そのスケジューリング機能を独自のアプリに組み込むことができます。
一般的なパターンとして、Calendlyの予約がシステム内のアクションをトリガーするようにしたい場合があるでしょう。ユーザーがデモを予約すると、CRMが更新されます。コンサルテーションがスケジュールされると、アンケートが送信されます。会議がキャンセルされると、チームに通知されます。
CalendlyのAPIは、これをWebhook経由で処理します。イベントが発生すると(予約の作成、キャンセル、再スケジュール)、CalendlyはエンドポイントにPOSTします。あなたはペイロードを処理し、アクションを実行します。
OAuth 2.0による認証
CalendlyはAPIアクセスにOAuth 2.0を使用します。単にAPIキーを使用することはできません。
OAuthアプリケーションの作成
- Calendly → 統合 → APIとWebhookに移動します。
- 「新規アプリケーションを作成」をクリックします。
- リダイレクトURIを設定します(例:
https://yourapp.com/auth/calendly/callback)。 - クライアントIDとクライアントシークレットを取得します。
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"
リフレッシュトークン
アクセストークンは2時間で期限切れになります。新しいアクセストークンを取得するにはリフレッシュトークンを使用します。
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
}
]
}
リアルタイム更新のためのWebhook
Webhookは、予約イベントについてリアルタイムでアプリに通知します。
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は、Calendly-Webhook-Signatureヘッダーに署名を含めてWebhookに署名します。
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')
}
// Webhookを処理
handleWebhook(req.body)
res.status(200).send('OK')
})
予約イベントの処理
function handleWebhook(payload) {
const { event, payload: data } = payload
switch (event) {
case 'invitee.created':
console.log(`新しい予約: ${data.event.start_time}`)
console.log(`招待者: ${data.email}`)
// 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
}
}
Apidogを使ったテスト
CalendlyのAPIは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署名が有効', () => {
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')
// 署名を検証
const valid = verifySignature(payload, signature, secret)
pm.expect(valid).to.be.true
})
ApidogでCalendlyのWebhookを無料でテストする
一般的なエラーと修正
401 Unauthorized(認証なし)
原因: 無効なトークンまたは期限切れのトークン。
修正:
- トークンが期限切れになっていないか確認する(2時間で期限切れ)。
- リフレッシュトークンを使用して新しいアクセストークンを取得する。
- Authorizationヘッダーが
Bearer {token}であることを確認する。
403 Forbidden(禁止)
原因: OAuthスコープが不足している。
修正: OAuthトークンには適切なスコープが必要です。承認を要求する際に必要なスコープを含めてください。Calendlyのスコープは、ユーザーが承認した内容に基づいて暗黙的に決定されます。
404 Not Found(見つかりません)
原因: リソースが存在しないか、ユーザーにアクセス権がない。
修正:
- リソースURIが正しいことを確認する。
- 認証されたユーザーがリソースへのアクセス権を持っていることを確認する。
- イベントタイプまたはイベントIDが有効であることを確認する。
422 Unprocessable Entity(処理できないエンティティ)
原因: リクエストのバリデーションエラー。
修正: 詳細についてはレスポンスを確認してください。
{
"title": "Validation Error",
"message": "Invalid parameter: url must be a valid HTTPS URL"
}
代替手段と比較
| 機能 | Calendly | Acuity | Cal.com | Calendly |
|---|---|---|---|---|
| 無料ティア | 制限あり | 制限あり | セルフホストは無料 | ✓ |
| APIアクセス | ✓ | ✓ | ✓ | ✓ |
| Webhook | ✓ | ✓ | ✓ | ✓ |
| OAuth | ✓ | APIキー | APIキー | OAuth |
| チームスケジューリング | ✓ | ✓ | ✓ | ✓ |
| オープンソース | いいえ | いいえ | はい | いいえ |
Calendlyは最も洗練されたAPIドキュメントとOAuthフローを持っています。Cal.comは、よりシンプルなAPIキー認証を備えたオープンソースの代替手段です。
実世界のユースケース
営業CRM連携。 B2B SaaS企業が価格設定ページにCalendlyを埋め込んでいます。誰かがデモを予約すると、Webhookが次をトリガーします。
- Salesforceでリードを作成する
- 営業チームにSlack通知を送信する
- マーケティングオートメーションシーケンスに追加する
- 顧客成功プラットフォームに活動をログする
コンサルテーションプラットフォーム。 法律サービスプラットフォームが、クライアントが弁護士とのコンサルテーションを予約できるようにしています。API連携により:
- 予約を内部スケジューリングシステムと同期する
- Zoom会議リンクを生成する
- 24時間前に初回アンケートを送信する
- 会議完了時にケースファイルを作成する
面接スケジューリング。 採用プラットフォームが、候補者の面接にCalendlyを使用しています。Webhookが次を実行します。
- ATSを面接詳細で更新する
- 採用担当者にメールで通知する
- すべての参加者にカレンダー招待を送信する
- フォローアップのために無断欠席者を追跡する
結論
学んだことは以下の通りです。
- CalendlyはAPI認証にOAuth 2.0を使用します
- APIを介してイベントタイプとスケジュールされたイベントにアクセスします
- Webhookはリアルタイムの予約通知を提供します
- セキュリティのために常にWebhook署名を検証してください
- 実際のカレンダーに接続する前にApidogでテストしてください
次のステップ:
- CalendlyでOAuthアプリケーションを作成する
- OAuthフローを実装する
- Webhookサブスクリプションを設定する
- Apidogでモックペイロードをテストする
- 本番環境にデプロイする
ApidogでCalendlyのWebhookを無料でテストする
よくある質問
APIを使用するために有料のCalendlyプランが必要ですか?
いいえ。APIは無料プランを含むすべてのプランで利用可能です。ただし、無料プランには機能の制限があります。Webhookはすべてのプランで利用できます。
ユーザーレベルと組織レベルのWebhookの違いは何ですか?
ユーザーレベルのWebhookは1人のユーザーのイベントのみをキャプチャします。組織レベルのWebhookはすべてのチームメンバーのイベントをキャプチャします。ほとんどの連携では組織スコープを使用します。
Webhook署名シークレットはどのように入手できますか?
API経由でWebhookを作成すると、レスポンスにsigning_keyが含まれます。これを安全に保管してください。これはWebhook署名を検証するために使用されます。
API経由で予約を作成できますか?
いいえ。Calendlyには予約を作成するAPIエンドポイントはありません。予約はCalendlyのUIまたは埋め込みウィジェットを介して行う必要があります。APIは予約に対して読み取り専用です。
タイムゾーンの変換はどのように処理しますか?
API内のすべてのタイムスタンプはUTC(ISO 8601)です。アプリケーションで現地時間に変換してください。ユーザーのタイムゾーンはユーザーリソースで利用できます。
レート制限はありますか?
Calendlyはレート制限を公に文書化していません。妥当なリクエストパターンを使用してください。制限に達した場合は、指数関数的バックオフを実装してください。
過去の予約を取得できますか?
はい。min_start_timeとmax_start_timeを使用して過去のイベントをクエリできます。過去にさかのぼってクエリできる期間に制限はありません。
OAuthフローをローカルでテストするにはどうすればよいですか?
ngrokのようなトンネリングサービスを使用して、ローカルサーバーを公開します。リダイレクトURIをngrokのURLに設定します。ブラウザでOAuthフローを完了し、コールバックを検査します。
