cal-com
オープンソースの予約プラットフォームCal.comに関する専門的なアドバイスを提供し、開発者がCal.comの埋め込みウィジェットやAPIなどを活用して、自社のアプリケーションに予約機能を追加するのを支援するSkill。
📜 元の英語説明(参考)
Expert guidance for Cal.com, the open-source scheduling platform for building booking and appointment systems. Helps developers integrate Cal.com's embed widgets, REST API, and webhooks to add scheduling capabilities to their applications.
🇯🇵 日本人クリエイター向け解説
オープンソースの予約プラットフォームCal.comに関する専門的なアドバイスを提供し、開発者がCal.comの埋め込みウィジェットやAPIなどを活用して、自社のアプリケーションに予約機能を追加するのを支援するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o cal-com.zip https://jpskill.com/download/14715.zip && unzip -o cal-com.zip && rm cal-com.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/14715.zip -OutFile "$d\cal-com.zip"; Expand-Archive "$d\cal-com.zip" -DestinationPath $d -Force; ri "$d\cal-com.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
cal-com.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
cal-comフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Cal.com — スケジューリング基盤
概要
Cal.com は、予約およびアポイントメントシステムを構築するためのオープンソースのスケジューリングプラットフォームです。開発者は Cal.com の埋め込みウィジェット、REST API、および Webhook を統合して、アプリケーションにスケジューリング機能を追加できます。
手順
埋め込みウィジェット
任意のウェブサイトに予約ウィジェットを追加します。
// src/components/BookingWidget.tsx — React アプリに Cal.com のスケジューリングを埋め込む
import Cal, { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react";
export function BookingWidget() {
useEffect(() => {
(async () => {
const cal = await getCalApi();
// 埋め込みの外観を設定します
cal("ui", {
theme: "light",
styles: { branding: { brandColor: "#6366f1" } },
hideEventTypeDetails: false,
layout: "month_view", // "month_view" | "week_view" | "column_view"
});
})();
}, []);
return (
<Cal
calLink="your-team/discovery-call" // Cal.com のイベントリンク
style={{ width: "100%", height: "100%", overflow: "scroll" }}
config={{
layout: "month_view",
name: "Customer Name", // ゲストの名前を事前入力
email: "customer@example.com", // ゲストのメールアドレスを事前入力
notes: "Interested in Enterprise plan",
}}
/>
);
}
// ポップアップでカレンダーを開くフローティングボタン
export function BookingButton() {
useEffect(() => {
(async () => {
const cal = await getCalApi();
cal("floatingButton", {
calLink: "your-team/discovery-call",
buttonText: "Book a Demo",
buttonColor: "#6366f1",
buttonTextColor: "#ffffff",
buttonPosition: "bottom-right",
});
})();
}, []);
return null; // フローティングボタンはそれ自体をレンダリングします
}
REST API 統合
予約、イベントタイプ、および可用性をプログラムで管理します。
// src/cal/client.ts — サーバーサイド操作用の Cal.com API クライアント
const CAL_API_URL = "https://api.cal.com/v2";
const CAL_API_KEY = process.env.CAL_API_KEY!;
async function calFetch(path: string, options?: RequestInit) {
const response = await fetch(`${CAL_API_URL}${path}`, {
...options,
headers: {
"Content-Type": "application/json",
"cal-api-version": "2024-08-13", // 安定性のために API バージョンを固定
Authorization: `Bearer ${CAL_API_KEY}`,
...options?.headers,
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Cal.com API error: ${error.message}`);
}
return response.json();
}
// 新しいイベントタイプを作成します (例: "30-min Discovery Call")
async function createEventType(params: {
title: string;
slug: string;
lengthInMinutes: number;
description?: string;
locations?: { type: string; link?: string }[];
}) {
return calFetch("/event-types", {
method: "POST",
body: JSON.stringify({
title: params.title,
slug: params.slug,
lengthInMinutes: params.lengthInMinutes,
description: params.description,
locations: params.locations ?? [
{ type: "integrations:google:meet" }, // デフォルト: Google Meet
],
bookingFields: [
{ name: "company", type: "text", label: "Company Name", required: true },
{ name: "teamSize", type: "select", label: "Team Size",
options: ["1-10", "11-50", "51-200", "200+"], required: true },
],
}),
});
}
// ある日付範囲で利用可能な時間枠を取得します
async function getAvailability(params: {
eventTypeId: number;
startTime: string; // ISO 8601
endTime: string;
timeZone: string;
}) {
const query = new URLSearchParams({
eventTypeId: String(params.eventTypeId),
startTime: params.startTime,
endTime: params.endTime,
timeZone: params.timeZone,
});
return calFetch(`/slots?${query}`);
}
// 予約を作成します
async function createBooking(params: {
eventTypeId: number;
start: string; // ISO 8601 datetime
attendee: { name: string; email: string; timeZone: string };
metadata?: Record<string, string>;
}) {
return calFetch("/bookings", {
method: "POST",
body: JSON.stringify({
eventTypeId: params.eventTypeId,
start: params.start,
attendee: params.attendee,
metadata: params.metadata,
language: "en",
}),
});
}
// 予約をキャンセルします
async function cancelBooking(bookingUid: string, reason?: string) {
return calFetch(`/bookings/${bookingUid}/cancel`, {
method: "POST",
body: JSON.stringify({ reason }),
});
}
// 予約のスケジュールを変更します
async function rescheduleBooking(bookingUid: string, newStart: string) {
return calFetch(`/bookings/${bookingUid}/reschedule`, {
method: "POST",
body: JSON.stringify({ start: newStart }),
});
}
Webhook
予約イベントにリアルタイムで対応します。
// app/api/cal-webhook/route.ts — Cal.com の Webhook イベントを処理します
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";
const WEBHOOK_SECRET = process.env.CAL_WEBHOOK_SECRET!;
// Webhook シグネチャを検証して、それが Cal.com からのものであることを確認します
function verifySignature(payload: string, signature: string): boolean {
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
export async function POST(request: NextRequest) {
const payload = await request.text();
const signature = request.headers.get("x-cal-signature-256") ?? "";
if (!verifySignature(payload, signature)) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
const event = JSON.parse(payload);
switch (event.triggerEvent) {
case "BOOKING_CREATED":
// 新しい予約 — 確認を送信、CRM を更新、営業に通知
await handleNewBooking({
bookingId: event.payload.bookingId,
attendeeName: event.payload.attendees[0]?.name,
attendeeEmail: event.payload.att 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Cal.com — Scheduling Infrastructure
Overview
Cal.com, the open-source scheduling platform for building booking and appointment systems. Helps developers integrate Cal.com's embed widgets, REST API, and webhooks to add scheduling capabilities to their applications.
Instructions
Embed Widget
Add a booking widget to any website:
// src/components/BookingWidget.tsx — Embed Cal.com scheduling in a React app
import Cal, { getCalApi } from "@calcom/embed-react";
import { useEffect } from "react";
export function BookingWidget() {
useEffect(() => {
(async () => {
const cal = await getCalApi();
// Configure the embed appearance
cal("ui", {
theme: "light",
styles: { branding: { brandColor: "#6366f1" } },
hideEventTypeDetails: false,
layout: "month_view", // "month_view" | "week_view" | "column_view"
});
})();
}, []);
return (
<Cal
calLink="your-team/discovery-call" // Your Cal.com event link
style={{ width: "100%", height: "100%", overflow: "scroll" }}
config={{
layout: "month_view",
name: "Customer Name", // Pre-fill guest name
email: "customer@example.com", // Pre-fill guest email
notes: "Interested in Enterprise plan",
}}
/>
);
}
// Floating button that opens calendar in a popup
export function BookingButton() {
useEffect(() => {
(async () => {
const cal = await getCalApi();
cal("floatingButton", {
calLink: "your-team/discovery-call",
buttonText: "Book a Demo",
buttonColor: "#6366f1",
buttonTextColor: "#ffffff",
buttonPosition: "bottom-right",
});
})();
}, []);
return null; // The floating button renders itself
}
REST API Integration
Manage bookings, event types, and availability programmatically:
// src/cal/client.ts — Cal.com API client for server-side operations
const CAL_API_URL = "https://api.cal.com/v2";
const CAL_API_KEY = process.env.CAL_API_KEY!;
async function calFetch(path: string, options?: RequestInit) {
const response = await fetch(`${CAL_API_URL}${path}`, {
...options,
headers: {
"Content-Type": "application/json",
"cal-api-version": "2024-08-13", // Pin API version for stability
Authorization: `Bearer ${CAL_API_KEY}`,
...options?.headers,
},
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Cal.com API error: ${error.message}`);
}
return response.json();
}
// Create a new event type (e.g., "30-min Discovery Call")
async function createEventType(params: {
title: string;
slug: string;
lengthInMinutes: number;
description?: string;
locations?: { type: string; link?: string }[];
}) {
return calFetch("/event-types", {
method: "POST",
body: JSON.stringify({
title: params.title,
slug: params.slug,
lengthInMinutes: params.lengthInMinutes,
description: params.description,
locations: params.locations ?? [
{ type: "integrations:google:meet" }, // Default: Google Meet
],
bookingFields: [
{ name: "company", type: "text", label: "Company Name", required: true },
{ name: "teamSize", type: "select", label: "Team Size",
options: ["1-10", "11-50", "51-200", "200+"], required: true },
],
}),
});
}
// Get available time slots for a date range
async function getAvailability(params: {
eventTypeId: number;
startTime: string; // ISO 8601
endTime: string;
timeZone: string;
}) {
const query = new URLSearchParams({
eventTypeId: String(params.eventTypeId),
startTime: params.startTime,
endTime: params.endTime,
timeZone: params.timeZone,
});
return calFetch(`/slots?${query}`);
}
// Create a booking
async function createBooking(params: {
eventTypeId: number;
start: string; // ISO 8601 datetime
attendee: { name: string; email: string; timeZone: string };
metadata?: Record<string, string>;
}) {
return calFetch("/bookings", {
method: "POST",
body: JSON.stringify({
eventTypeId: params.eventTypeId,
start: params.start,
attendee: params.attendee,
metadata: params.metadata,
language: "en",
}),
});
}
// Cancel a booking
async function cancelBooking(bookingUid: string, reason?: string) {
return calFetch(`/bookings/${bookingUid}/cancel`, {
method: "POST",
body: JSON.stringify({ reason }),
});
}
// Reschedule a booking
async function rescheduleBooking(bookingUid: string, newStart: string) {
return calFetch(`/bookings/${bookingUid}/reschedule`, {
method: "POST",
body: JSON.stringify({ start: newStart }),
});
}
Webhooks
React to booking events in real time:
// app/api/cal-webhook/route.ts — Handle Cal.com webhook events
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";
const WEBHOOK_SECRET = process.env.CAL_WEBHOOK_SECRET!;
// Verify the webhook signature to ensure it's from Cal.com
function verifySignature(payload: string, signature: string): boolean {
const expected = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
export async function POST(request: NextRequest) {
const payload = await request.text();
const signature = request.headers.get("x-cal-signature-256") ?? "";
if (!verifySignature(payload, signature)) {
return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
}
const event = JSON.parse(payload);
switch (event.triggerEvent) {
case "BOOKING_CREATED":
// New booking — send confirmation, update CRM, notify sales
await handleNewBooking({
bookingId: event.payload.bookingId,
attendeeName: event.payload.attendees[0]?.name,
attendeeEmail: event.payload.attendees[0]?.email,
startTime: event.payload.startTime,
eventType: event.payload.eventTitle,
metadata: event.payload.metadata,
});
break;
case "BOOKING_CANCELLED":
// Booking cancelled — update CRM, free up resources
await handleCancellation({
bookingId: event.payload.bookingId,
reason: event.payload.cancellationReason,
});
break;
case "BOOKING_RESCHEDULED":
// Booking moved — update calendar integrations
await handleReschedule({
bookingId: event.payload.bookingId,
oldTime: event.payload.previousStartTime,
newTime: event.payload.startTime,
});
break;
case "MEETING_ENDED":
// Meeting finished — trigger follow-up sequence
await triggerFollowUp(event.payload.bookingId);
break;
}
return NextResponse.json({ received: true });
}
async function handleNewBooking(booking: any) {
// Example: Create a deal in your CRM
await crm.createDeal({
name: `Demo: ${booking.attendeeName}`,
contact: booking.attendeeEmail,
stage: "discovery",
source: "website-booking",
metadata: booking.metadata,
});
// Notify the sales team via Slack
await slack.postMessage({
channel: "#sales-notifications",
text: `📅 New ${booking.eventType} booked!\n👤 ${booking.attendeeName} (${booking.attendeeEmail})\n🕐 ${new Date(booking.startTime).toLocaleString()}`,
});
}
Managing Team Availability
Configure round-robin scheduling and team calendars:
// src/cal/team-setup.ts — Configure team scheduling rules
async function setupTeamScheduling() {
// Create a team event type with round-robin assignment
const eventType = await calFetch("/event-types", {
method: "POST",
body: JSON.stringify({
title: "Product Demo",
slug: "product-demo",
lengthInMinutes: 45,
schedulingType: "ROUND_ROBIN", // Rotate among team members
hosts: [
{ userId: 101, isFixed: false }, // Participates in rotation
{ userId: 102, isFixed: false },
{ userId: 103, isFixed: true }, // Always included (e.g., sales engineer)
],
beforeEventBuffer: 15, // 15-min buffer before meetings
afterEventBuffer: 10, // 10-min buffer after
minimumBookingNotice: 120, // Minimum 2 hours notice
slotInterval: 15, // Show slots every 15 minutes
locations: [
{ type: "integrations:zoom" }, // Auto-create Zoom meeting
],
}),
});
// Set working hours for the team
await calFetch("/schedules", {
method: "POST",
body: JSON.stringify({
name: "Business Hours",
timeZone: "America/New_York",
isDefault: true,
availability: [
// Monday-Friday 9 AM to 5 PM
{ days: [1, 2, 3, 4, 5], startTime: "09:00", endTime: "17:00" },
],
// Block specific dates (holidays, company events)
dateOverrides: [
{ date: "2026-12-25", startTime: null, endTime: null }, // Christmas — unavailable
{ date: "2026-12-31", startTime: "09:00", endTime: "12:00" }, // NYE — morning only
],
}),
});
}
Installation
# React embed
npm install @calcom/embed-react
# For self-hosted Cal.com (Docker)
git clone https://github.com/calcom/cal.com.git
cd cal.com
cp .env.example .env
docker compose up -d
Examples
Example 1: Setting up Cal Com with a custom configuration
User request:
I just installed Cal Com. Help me configure it for my TypeScript + React workflow with my preferred keybindings.
The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.
Example 2: Extending Cal Com with custom functionality
User request:
I want to add a custom rest api integration to Cal Com. How do I build one?
The agent scaffolds the extension/plugin project, implements the core functionality following Cal Com's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.
Guidelines
- Use embed for public booking — The React embed handles time zones, availability, and confirmations automatically
- Pin API versions — Include
cal-api-versionheader to avoid breaking changes when Cal.com updates - Verify webhook signatures — Always validate
x-cal-signature-256to prevent spoofed events - Buffer time between meetings — Set
beforeEventBufferandafterEventBufferto prevent back-to-back meetings - Pre-fill known data — Pass name, email, and context via embed config to reduce friction for returning users
- Use metadata for attribution — Pass UTM params, plan interest, or referral codes through booking metadata
- Handle all webhook events — Don't just handle BOOKING_CREATED; cancellations and reschedules need cleanup too
- Self-host for compliance — If you need data residency (GDPR, HIPAA), self-host Cal.com with Docker