API Reference

Complete API reference for Calendar endpoints.

Authentication

All Calendar API endpoints require authentication:

Authorization: Bearer YOUR_API_KEY

Or use the X-API-Key header:

X-API-Key: YOUR_API_KEY

Base URL

https://api.usetransactional.com/calendar

Event Types

Create Event Type

POST /calendar/event-types

Body:

{
  "title": "Product Demo",
  "slug": "demo",
  "duration": 30,
  "description": "See our product in action",
  "location": {
    "type": "GOOGLE_MEET"
  },
  "scheduleId": "schedule_xxx",
  "bufferBefore": 5,
  "bufferAfter": 10,
  "minimumNotice": 60,
  "maximumAdvance": 60
}

List Event Types

GET /calendar/event-types

Get Event Type

GET /calendar/event-types/{eventTypeId}

Update Event Type

PATCH /calendar/event-types/{eventTypeId}

Delete Event Type

DELETE /calendar/event-types/{eventTypeId}

Schedules

Create Schedule

POST /calendar/schedules

Body:

{
  "name": "Work Hours",
  "timezone": "America/New_York",
  "isDefault": true,
  "availability": [
    { "day": "MONDAY", "startTime": "09:00", "endTime": "17:00" },
    { "day": "TUESDAY", "startTime": "09:00", "endTime": "17:00" },
    { "day": "WEDNESDAY", "startTime": "09:00", "endTime": "17:00" },
    { "day": "THURSDAY", "startTime": "09:00", "endTime": "17:00" },
    { "day": "FRIDAY", "startTime": "09:00", "endTime": "17:00" }
  ]
}

List Schedules

GET /calendar/schedules

Get Schedule

GET /calendar/schedules/{scheduleId}

Update Schedule

PATCH /calendar/schedules/{scheduleId}

Delete Schedule

DELETE /calendar/schedules/{scheduleId}

Add Date Override

POST /calendar/schedules/{scheduleId}/overrides

Body:

{
  "date": "2024-12-25",
  "isAvailable": false,
  "reason": "Christmas Day"
}

Remove Date Override

DELETE /calendar/schedules/{scheduleId}/overrides/{overrideId}

Availability

Get Available Slots

GET /calendar/availability

Query Parameters:

ParameterTypeDescription
eventTypeIdstringEvent type ID (required)
startDatestringStart date (YYYY-MM-DD)
endDatestringEnd date (YYYY-MM-DD)
timezonestringResponse timezone
hostIdstringFilter by specific host
durationnumberFor multi-duration events

Response:

{
  "days": [
    {
      "date": "2024-01-15",
      "slots": [
        { "startTime": "09:00", "endTime": "09:30" },
        { "startTime": "09:30", "endTime": "10:00" }
      ]
    }
  ]
}

Bookings

Create Booking

POST /calendar/bookings

Body:

{
  "eventTypeId": "evt_xxx",
  "startTime": "2024-01-15T10:00:00-05:00",
  "attendee": {
    "name": "John Doe",
    "email": "john@example.com",
    "timezone": "America/New_York"
  },
  "notes": "Looking forward to the meeting",
  "responses": {
    "company": "Acme Corp"
  },
  "metadata": {
    "source": "website"
  }
}

Response:

{
  "uid": "booking_xxx",
  "eventTypeId": "evt_xxx",
  "status": "CONFIRMED",
  "startTime": "2024-01-15T15:00:00.000Z",
  "endTime": "2024-01-15T15:30:00.000Z",
  "attendee": {
    "name": "John Doe",
    "email": "john@example.com",
    "timezone": "America/New_York"
  },
  "host": {
    "id": "user_xxx",
    "name": "Jane Smith",
    "email": "jane@company.com"
  },
  "meetingUrl": "https://meet.google.com/xxx",
  "rescheduleUrl": "https://calendar.usetransactional.com/reschedule/xxx",
  "cancelUrl": "https://calendar.usetransactional.com/cancel/xxx"
}

List Bookings

GET /calendar/bookings

Query Parameters:

ParameterTypeDescription
countnumberResults per page (max 100)
offsetnumberPagination offset
statusstringFilter by status
startDatestringFilter by date range start
endDatestringFilter by date range end
eventTypeIdstringFilter by event type
attendeeEmailstringFilter by attendee

Get Booking

GET /calendar/bookings/{bookingUid}

Cancel Booking

POST /calendar/bookings/{bookingUid}/cancel

Body:

{
  "reason": "Schedule conflict",
  "cancelledBy": "attendee",
  "notifyHost": true
}

Reschedule Booking

POST /calendar/bookings/{bookingUid}/reschedule

Body:

{
  "startTime": "2024-01-20T14:00:00-05:00",
  "reason": "Need to move to next week",
  "notifyAttendee": true
}

Confirm Booking

POST /calendar/bookings/{bookingUid}/confirm

Reject Booking

POST /calendar/bookings/{bookingUid}/reject

Body:

{
  "reason": "Not available at this time"
}

Webhooks

Create Webhook

POST /calendar/webhooks

Body:

{
  "url": "https://yourapp.com/webhooks/calendar",
  "events": ["booking.created", "booking.cancelled"]
}

List Webhooks

GET /calendar/webhooks

Get Webhook

GET /calendar/webhooks/{webhookId}

Update Webhook

PATCH /calendar/webhooks/{webhookId}

Delete Webhook

DELETE /calendar/webhooks/{webhookId}

List Deliveries

GET /calendar/webhooks/{webhookId}/deliveries

SDK Reference

TypeScript SDK

import { Transactional } from '@usetransactional/node';
 
const client = new Transactional({
  apiKey: process.env.TRANSACTIONAL_API_KEY,
});
 
// Event Types
const eventType = await client.calendar.eventTypes.create({ title, slug, duration });
const eventTypes = await client.calendar.eventTypes.list();
await client.calendar.eventTypes.update(id, { title });
await client.calendar.eventTypes.delete(id);
 
// Schedules
const schedule = await client.calendar.schedules.create({ name, timezone, availability });
const schedules = await client.calendar.schedules.list();
await client.calendar.schedules.update(id, { availability });
await client.calendar.schedules.addOverride(id, { date, isAvailable });
 
// Availability
const slots = await client.calendar.availability.get({
  eventTypeId,
  startDate,
  endDate,
});
 
// Bookings
const booking = await client.calendar.bookings.create({
  eventTypeId,
  startTime,
  attendee,
});
const bookings = await client.calendar.bookings.list({ status: 'CONFIRMED' });
await client.calendar.bookings.cancel(uid, { reason });
await client.calendar.bookings.reschedule(uid, { startTime });
 
// Webhooks
const webhook = await client.calendar.webhooks.create({ url, events });

Python SDK

from usetransactional import Transactional
 
client = Transactional(api_key="your_api_key")
 
# Event Types
event_type = client.calendar.event_types.create(title=title, slug=slug, duration=duration)
event_types = client.calendar.event_types.list()
client.calendar.event_types.update(id, title=title)
client.calendar.event_types.delete(id)
 
# Schedules
schedule = client.calendar.schedules.create(
    name=name,
    timezone=timezone,
    availability=availability
)
 
# Availability
slots = client.calendar.availability.get(
    event_type_id=event_type_id,
    start_date=start_date,
    end_date=end_date
)
 
# Bookings
booking = client.calendar.bookings.create(
    event_type_id=event_type_id,
    start_time=start_time,
    attendee=attendee
)
client.calendar.bookings.cancel(uid, reason=reason)
client.calendar.bookings.reschedule(uid, start_time=new_time)
 
# Webhooks
webhook = client.calendar.webhooks.create(url=url, events=events)

Error Codes

HTTP StatusCodeDescription
400INVALID_REQUESTInvalid request body
401UNAUTHORIZEDInvalid or missing API key
403FORBIDDENInsufficient permissions
404NOT_FOUNDResource not found
409CONFLICTBooking conflict
429RATE_LIMITEDToo many requests

Calendar-Specific Errors

CodeDescription
SLOT_UNAVAILABLETime slot no longer available
PAST_BOOKINGCannot book in the past
MINIMUM_NOTICEBooking too close to start time
MAXIMUM_ADVANCEBooking too far in advance
DAILY_LIMITDaily booking limit reached
INVALID_TIMEZONEInvalid timezone specified
HOST_UNAVAILABLESelected host not available
EVENT_TYPE_INACTIVEEvent type is disabled