GudCalGudCal
Docs
API Reference

API Reference

Complete REST API documentation for GudCal. Create event types, manage availability, handle bookings, and run your entire scheduling operation programmatically.

GudCal provides a comprehensive REST API that lets users and AI agents manage their entire scheduling operation without touching the web interface. From creating event types to managing availability and handling bookings — everything is available via API.

Base URL

https://your-gudcal-instance.com/api/v1

All authenticated endpoints are under the /api/v1 namespace. Public endpoints (availability queries, booking creation by guests) use the legacy /api namespace.

Authentication

API requests to private endpoints require an API key. Generate one from Dashboard > Settings > API Keys, or use the POST /api/v1/api-keys endpoint.

API keys use the gck_ prefix and are passed via the Authorization header:

curl -H "Authorization: Bearer gck_your_api_key_here" \
  https://gudcal.com/api/v1/me

Getting Your First API Key

  1. Register at https://gudcal.com/register (email/password or Google OAuth)
  2. Go to Dashboard > Settings > API Keys
  3. Click Create API Key, give it a name, and copy the key
  4. The full key is only shown once — store it securely
  5. Hand this key to your AI agent — from here on, the agent can manage everything

Error Responses

All endpoints return errors in a consistent format:

{
  "error": "Description of what went wrong"
}

Common HTTP status codes:

CodeMeaning
200Success
201Created
400Bad request (invalid input)
401Unauthorized (missing or invalid API key)
404Resource not found
409Conflict (e.g. duplicate slug)
429Rate limited

Profile

Get Profile

GET /api/v1/me

Returns the authenticated user's profile.

Response:

{
  "id": "clx...",
  "name": "Tim Uzua",
  "email": "tim@gudcal.com",
  "username": "tim",
  "timezone": "America/New_York",
  "bio": "Building GudCal",
  "weekStart": 1
}

Update Profile

PUT /api/v1/me

Update profile fields. All fields are optional — only provided fields are updated.

Body:

{
  "name": "Tim Uzua",
  "username": "tim",
  "timezone": "Africa/Lagos",
  "bio": "Building open-source scheduling",
  "weekStart": 1
}
FieldTypeDescription
namestringDisplay name
usernamestringUnique username (letters, numbers, hyphens, underscores)
timezonestringIANA timezone (e.g. America/New_York)
biostringShort bio (max 500 chars)
weekStartnumberWeek start day (0=Sunday, 1=Monday, ...6=Saturday)

Event Types

List Event Types

GET /api/v1/event-types

Returns all event types for the authenticated user (including inactive ones).

Response:

[
  {
    "id": "clx...",
    "title": "30-Minute Call",
    "slug": "30-min-call",
    "description": "A quick intro call",
    "duration": 30,
    "locationType": "GOOGLE_MEET",
    "isActive": true,
    "requiresConfirmation": false,
    "bufferBefore": 5,
    "bufferAfter": 5,
    "minimumNotice": 120,
    "maxBookingsPerDay": null,
    "slotInterval": null,
    "color": "#0069FF",
    "availability": { "id": "clx...", "name": "Working Hours" },
    "bookingCount": 42
  }
]

Get Event Type

GET /api/v1/event-types/:id

Returns a single event type with booking count.

Create Event Type

POST /api/v1/event-types

Body:

{
  "title": "Discovery Call",
  "slug": "discovery-call",
  "description": "Let's explore how we can work together",
  "duration": 45,
  "locationType": "GOOGLE_MEET",
  "requiresConfirmation": false,
  "bufferBefore": 5,
  "bufferAfter": 10,
  "minimumNotice": 240,
  "maxBookingsPerDay": 5
}
FieldTypeRequiredDescription
titlestringyesEvent type title
slugstringyesURL slug (lowercase, hyphens only)
descriptionstringnoDescription
durationnumbernoDuration in minutes (default: 30)
locationTypeenumnoIN_PERSON, GOOGLE_MEET, ZOOM, PHONE, CUSTOM
locationValuestringnoAddress, phone, or custom URL
isActivebooleannoWhether active (default: true)
requiresConfirmationbooleannoRequire manual confirmation (default: false)
bufferBeforenumbernoBuffer before in minutes (default: 0)
bufferAfternumbernoBuffer after in minutes (default: 0)
minimumNoticenumbernoMinimum advance notice in minutes (default: 120)
maxBookingsPerDaynumbernoMax bookings per day (null = unlimited)
slotIntervalnumbernoCustom slot interval in minutes
colorstringnoHex color (default: #0069FF)
availabilityIdstringnoLink to an availability schedule

Response (201):

{
  "id": "clx...",
  "title": "Discovery Call",
  "slug": "discovery-call",
  "duration": 45,
  "isActive": true,
  "bookingUrl": "https://gudcal.com/tim/discovery-call"
}

Update Event Type

PUT /api/v1/event-types/:id

All fields are optional. Only provided fields are updated.

Body:

{
  "title": "Updated Call",
  "duration": 60,
  "isActive": false
}

Delete Event Type

DELETE /api/v1/event-types/:id

Deletes the event type and all associated bookings.


Availability

List Availability Schedules

GET /api/v1/availability

Returns all availability schedules with their weekly rules and date overrides.

Response:

[
  {
    "id": "clx...",
    "name": "Working Hours",
    "timezone": "America/New_York",
    "isDefault": true,
    "rules": [
      { "dayOfWeek": 1, "startTime": "09:00", "endTime": "17:00" },
      { "dayOfWeek": 2, "startTime": "09:00", "endTime": "17:00" },
      { "dayOfWeek": 3, "startTime": "09:00", "endTime": "17:00" },
      { "dayOfWeek": 4, "startTime": "09:00", "endTime": "17:00" },
      { "dayOfWeek": 5, "startTime": "09:00", "endTime": "17:00" }
    ],
    "dateOverrides": [
      { "date": "2025-12-25", "isBlocked": true }
    ]
  }
]

Get Availability Schedule

GET /api/v1/availability/:id

Create Availability Schedule

POST /api/v1/availability

Body:

{
  "name": "Business Hours",
  "timezone": "America/New_York",
  "isDefault": true,
  "rules": [
    { "dayOfWeek": 1, "startTime": "09:00", "endTime": "12:00" },
    { "dayOfWeek": 1, "startTime": "13:00", "endTime": "17:00" },
    { "dayOfWeek": 2, "startTime": "09:00", "endTime": "17:00" },
    { "dayOfWeek": 3, "startTime": "09:00", "endTime": "17:00" },
    { "dayOfWeek": 4, "startTime": "09:00", "endTime": "17:00" },
    { "dayOfWeek": 5, "startTime": "09:00", "endTime": "15:00" }
  ]
}
FieldTypeRequiredDescription
namestringnoSchedule name (default: "Working Hours")
timezonestringnoIANA timezone (default: user's timezone)
isDefaultbooleannoSet as default schedule
rulesarrayyesWeekly availability rules
rules[].dayOfWeeknumberyesDay of week (0=Sunday ... 6=Saturday)
rules[].startTimestringyesStart time in HH:mm (e.g. "09:00")
rules[].endTimestringyesEnd time in HH:mm (e.g. "17:00")

Multiple rules per day are supported (e.g. morning + afternoon blocks with a lunch break).

Update Availability Schedule

PUT /api/v1/availability/:id

If rules or dateOverrides arrays are provided, they replace all existing rules/overrides.

Delete Availability Schedule

DELETE /api/v1/availability/:id

Cannot delete your only availability schedule.


Bookings

List Bookings

GET /api/v1/bookings

Query Parameters:

NameTypeDefaultDescription
filterenumupcomingupcoming, past, cancelled, pending, all
limitnumber20Max results (1-100)
offsetnumber0Skip N results for pagination

Response:

[
  {
    "uid": "abc-123-def",
    "eventType": "Discovery Call",
    "eventSlug": "discovery-call",
    "guestName": "Jane Doe",
    "guestEmail": "jane@example.com",
    "guestTimezone": "America/Chicago",
    "startTime": "2025-01-15T14:00:00.000Z",
    "endTime": "2025-01-15T14:45:00.000Z",
    "status": "CONFIRMED",
    "notes": "Looking forward to chatting!"
  }
]

Get Booking

GET /api/v1/bookings/:uid

Update Booking Status

PATCH /api/v1/bookings/:uid

Body:

{
  "action": "confirm"
}

Supported actions:

ActionFrom StatusTo StatusDescription
confirmPENDINGCONFIRMEDApprove a pending booking
cancelPENDING, CONFIRMEDCANCELLEDCancel with optional reason
no_showCONFIRMEDNO_SHOWMark guest as no-show

For cancel, you can include a reason field:

{
  "action": "cancel",
  "reason": "Schedule conflict"
}

API Keys

List API Keys

GET /api/v1/api-keys

Returns all API keys (masked for security).

Response:

[
  {
    "id": "clx...",
    "name": "My Agent Key",
    "key": "gck_a1b2...x9y0",
    "expiresAt": "2026-01-15T00:00:00.000Z",
    "lastUsed": "2025-06-10T14:30:00.000Z",
    "createdAt": "2025-01-01T00:00:00.000Z"
  }
]

Create API Key

POST /api/v1/api-keys

Body:

{
  "name": "Production Agent",
  "expiresInDays": 90
}
FieldTypeRequiredDescription
namestringyesDescriptive name for this key
expiresInDaysnumbernoKey expiration in days (null = never)

Response (201):

{
  "id": "clx...",
  "name": "Production Agent",
  "key": "gck_a1b2c3d4e5f6...",
  "expiresAt": "2025-04-15T00:00:00.000Z"
}

The full key is only returned once. Store it securely.

Revoke API Key

DELETE /api/v1/api-keys/:id

Permanently revokes the API key.


Public Endpoints

These endpoints do not require authentication and are used by guests to view availability and create bookings.

Get Available Slots

GET /api/availability/:username?eventSlug=slug&from=YYYY-MM-DD&to=YYYY-MM-DD&timezone=America/New_York
NameTypeRequiredDescription
usernamepathyesThe host's username
eventSlugqueryyesThe event type slug
fromquerynoStart date (defaults to today)
toquerynoEnd date (defaults to 7 days out)
timezonequerynoGuest timezone

Create a Booking (Guest)

POST /api/bookings
{
  "eventTypeId": "clx...",
  "startTime": "2025-01-15T14:00:00.000Z",
  "guestName": "Jane Doe",
  "guestEmail": "jane@example.com",
  "guestTimezone": "America/New_York",
  "notes": "Looking forward to our call"
}

Webhooks

Subscribe to real-time events by creating webhooks in Dashboard > Settings.

Supported Events

EventDescription
BOOKING_CREATEDA new booking was created
BOOKING_CONFIRMEDA pending booking was confirmed
BOOKING_CANCELLEDA booking was cancelled
BOOKING_RESCHEDULEDA booking was rescheduled
BOOKING_REMINDERA reminder was sent (24h before)
MEETING_ENDEDA meeting has ended

Webhook Payload

{
  "event": "BOOKING_CREATED",
  "data": {
    "bookingUid": "abc-123",
    "eventType": "30-min-call",
    "guestName": "Jane Doe",
    "guestEmail": "jane@example.com",
    "startTime": "2025-01-15T14:00:00.000Z",
    "endTime": "2025-01-15T14:30:00.000Z"
  },
  "timestamp": "2025-01-14T10:00:00.000Z"
}

Verifying Signatures

Each webhook includes an X-GudCal-Signature header with an HMAC-SHA256 signature:

import { createHmac } from "crypto";
 
function verifySignature(payload, signature, secret) {
  const expected = createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return expected === signature;
}

Rate Limits

API endpoints are rate-limited. If exceeded, you'll receive a 429 Too Many Requests response. Respect the Retry-After header value before retrying.


Full Agent Workflow Example

Once you've registered and created an API key from the dashboard, hand it to your agent. Here's what the agent can do from there:

# Step 1: Set up profile
curl -X PUT https://gudcal.com/api/v1/me \
  -H "Authorization: Bearer gck_your_key" \
  -H "Content-Type: application/json" \
  -d '{"username": "tim", "timezone": "Africa/Lagos"}'
 
# Step 2: Create availability schedule
curl -X POST https://gudcal.com/api/v1/availability \
  -H "Authorization: Bearer gck_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Business Hours",
    "timezone": "Africa/Lagos",
    "isDefault": true,
    "rules": [
      {"dayOfWeek": 1, "startTime": "09:00", "endTime": "17:00"},
      {"dayOfWeek": 2, "startTime": "09:00", "endTime": "17:00"},
      {"dayOfWeek": 3, "startTime": "09:00", "endTime": "17:00"},
      {"dayOfWeek": 4, "startTime": "09:00", "endTime": "17:00"},
      {"dayOfWeek": 5, "startTime": "09:00", "endTime": "15:00"}
    ]
  }'
 
# Step 3: Create event types
curl -X POST https://gudcal.com/api/v1/event-types \
  -H "Authorization: Bearer gck_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Quick Chat",
    "slug": "quick-chat",
    "duration": 15,
    "description": "A quick 15-minute chat"
  }'
 
curl -X POST https://gudcal.com/api/v1/event-types \
  -H "Authorization: Bearer gck_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Strategy Session",
    "slug": "strategy-session",
    "duration": 60,
    "requiresConfirmation": true,
    "bufferBefore": 10,
    "bufferAfter": 10
  }'
 
# Booking page is now live at gudcal.com/tim
 
# Step 4: Check pending bookings
curl https://gudcal.com/api/v1/bookings?filter=pending \
  -H "Authorization: Bearer gck_your_key"
 
# Step 5: Confirm a pending booking
curl -X PATCH https://gudcal.com/api/v1/bookings/abc-123 \
  -H "Authorization: Bearer gck_your_key" \
  -H "Content-Type: application/json" \
  -d '{"action": "confirm"}'