DEV Community

Alex Spinov
Alex Spinov

Posted on

Cal.com Has a Free API — Here's How to Build Scheduling Into Any App

A freelancer told me: 'I spent 3 hours per week going back and forth over email to schedule meetings. I added Cal.com to my site — now clients book directly. I got 3 hours of my life back every week.'

What Cal.com Offers for Free

Cal.com free tier:

  • Unlimited bookings on the free plan
  • 1 event type (enough for most solo use cases)
  • Calendar sync — Google Calendar, Outlook, Apple Calendar
  • Booking page — customizable scheduling page
  • REST API — full programmatic access
  • Webhooks — real-time booking notifications
  • Self-hosted — unlimited everything

Cal.com paid starts at $12/month for unlimited event types.

Quick Start (Self-Hosted)

git clone https://github.com/calcom/cal.com.git
cd cal.com
yarn install
yarn dev
# Access at http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

REST API

# Get your API key from Cal.com Settings > Developer > API Keys

# List event types
curl 'https://api.cal.com/v1/event-types?apiKey=YOUR_API_KEY'

# Get available slots
curl 'https://api.cal.com/v1/slots/available?apiKey=YOUR_API_KEY&eventTypeId=123&startTime=2026-04-01T00:00:00Z&endTime=2026-04-07T23:59:59Z'

# Create a booking
curl -X POST 'https://api.cal.com/v1/bookings?apiKey=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "eventTypeId": 123,
    "start": "2026-04-02T10:00:00Z",
    "end": "2026-04-02T10:30:00Z",
    "responses": {
      "name": "Alice Johnson",
      "email": "alice@example.com",
      "notes": "Discussing project scope"
    },
    "timeZone": "America/New_York"
  }'

# List bookings
curl 'https://api.cal.com/v1/bookings?apiKey=YOUR_API_KEY&status=upcoming'

# Cancel a booking
curl -X DELETE 'https://api.cal.com/v1/bookings/BOOKING_ID?apiKey=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"cancellationReason": "Schedule conflict"}'
Enter fullscreen mode Exit fullscreen mode

Embed in Your App

<!-- Inline embed -->
<script src="https://cal.com/embed.js"></script>
<cal-inline calLink="your-username/30min" />

<!-- Popup embed -->
<button onclick="Cal('ui', {styles: {branding: {brandColor: '#000'}}, calLink: 'your-username/30min'})">Book a Call</button>
Enter fullscreen mode Exit fullscreen mode

Node.js Integration

const CAL_API = 'https://api.cal.com/v1';
const API_KEY = process.env.CAL_API_KEY;

async function getAvailableSlots(eventTypeId, startDate, endDate) {
  const params = new URLSearchParams({
    apiKey: API_KEY,
    eventTypeId: String(eventTypeId),
    startTime: startDate,
    endTime: endDate
  });

  const res = await fetch(`${CAL_API}/slots/available?${params}`);
  const { slots } = await res.json();
  return slots;
}

async function createBooking(eventTypeId, start, end, attendee) {
  const res = await fetch(`${CAL_API}/bookings?apiKey=${API_KEY}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      eventTypeId,
      start,
      end,
      responses: attendee,
      timeZone: attendee.timeZone || 'UTC'
    })
  });
  return res.json();
}

// Get next available slot and book it
const slots = await getAvailableSlots(123, '2026-04-01', '2026-04-07');
if (Object.keys(slots).length > 0) {
  const firstDay = Object.keys(slots)[0];
  const firstSlot = slots[firstDay][0];
  await createBooking(123, firstSlot.time, null, {
    name: 'Alice',
    email: 'alice@example.com'
  });
}
Enter fullscreen mode Exit fullscreen mode

Webhooks

// Receive booking notifications
app.post('/webhooks/cal', (req, res) => {
  const { triggerEvent, payload } = req.body;

  switch (triggerEvent) {
    case 'BOOKING_CREATED':
      console.log(`New booking: ${payload.attendees[0].name} at ${payload.startTime}`);
      // Send Slack notification, add to CRM, etc.
      break;
    case 'BOOKING_CANCELLED':
      console.log(`Cancelled: ${payload.uid}`);
      break;
    case 'BOOKING_RESCHEDULED':
      console.log(`Rescheduled to: ${payload.startTime}`);
      break;
  }

  res.sendStatus(200);
});
Enter fullscreen mode Exit fullscreen mode

Use Cases

  • Freelancers — client booking page
  • SaaS — embed scheduling in onboarding flow
  • Sales teams — prospect scheduling
  • Support — customer support call booking
  • Internal — interview scheduling, 1:1s

Need to automate your business? Check out my web scraping actors on Apify — data collection on autopilot.

Need scheduling integration? Email me at spinov001@gmail.com.

Top comments (0)