API Documentation

Build AI agents and integrations with the Intervals API.

Base URL: https://intervals.so/api/v1

Authentication

All API requests require an API key in the Authorization header:

Authorization: Bearer ivl_live_xxxxxxxxxxxxx

Generate API keys in your dashboard → Settings → API Keys.

Rate Limits

Pro tier

1,000 requests/day

Free trial

100 requests/day

Error Handling

All errors return a consistent JSON format:

{
  "error": "Human-readable error message",
  "message": "Additional details (optional)",
  "details": [...]  // Validation errors only
}

Common Error Codes

400Bad Request — Invalid parameters or missing required fields
401Unauthorized — Invalid or missing API key
403Forbidden — API access not available for your tier
404Not Found — Resource doesn't exist
429Too Many Requests — Rate limit exceeded
500Internal Server Error — Something went wrong

Profile

GET/profile

Get your profile information

Request

curl https://intervals.so/api/v1/profile \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "user_id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Ruzgar",
  "timezone": "Europe/Tallinn",
  "subscription_tier": "pro",
  "calendar_connected": true,
  "default_duration": 30,
  "api_key_name": "My AI Assistant"
}

Response Fields

user_id(string)Your unique user ID
name(string)Display name
timezone(string)IANA timezone (e.g., "Europe/Tallinn")
subscription_tier(string)"free", "beta", or "pro"
calendar_connected(boolean)Whether Google Calendar is connected
default_duration(number)Default meeting duration in minutes
api_key_name(string)Name of the API key used for this request

Availability

GET/availability

Check availability for a specific date

Query Parameters

date(string)requiredDate in YYYY-MM-DD format

Request

curl "https://intervals.so/api/v1/availability?date=2026-02-06" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "date": "2026-02-06",
  "timezone": "Europe/Tallinn",
  "day_of_week": "friday",
  "working_hours": {
    "start": "09:00",
    "end": "17:00"
  },
  "intervals": [
    { "title": "Friday afternoon", "time_range": "13:00 – 17:00" }
  ],
  "busy_slots": [
    { "start": "14:00", "end": "14:30", "title": "Team Standup" }
  ],
  "available_slots": [
    { "start": "13:00", "end": "14:00" },
    { "start": "14:30", "end": "17:00" }
  ]
}

Response Fields

date(string)The requested date
timezone(string)User timezone
day_of_week(string)Day name (lowercase)
working_hours(object)Overall working window for the day
intervals(array)Active availability intervals for this day
busy_slots(array)Calendar events blocking time
available_slots(array)Free time windows
GET/availability/slots

Get bookable time slots for a date range. Ideal for AI agents finding meeting times.

Query Parameters

start(string)requiredStart date (YYYY-MM-DD)
end(string)requiredEnd date (YYYY-MM-DD), max 14 days from start
duration(number)Meeting duration in minutes (default: user setting)
buffer_before(number)Buffer before meeting in minutes (default: 15)
buffer_after(number)Buffer after meeting in minutes (default: 15)
limit(number)Max slots to return (default: 10, max: 50)

Request

curl "https://intervals.so/api/v1/availability/slots?start=2026-02-06&end=2026-02-10&duration=30&limit=5" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "timezone": "Europe/Tallinn",
  "duration_minutes": 30,
  "buffer_before_minutes": 15,
  "buffer_after_minutes": 15,
  "date_range": { "start": "2026-02-06", "end": "2026-02-10" },
  "total_slots": 5,
  "slots": [
    {
      "date": "2026-02-06",
      "start": "13:00",
      "end": "13:30",
      "iso_start": "2026-02-06T11:00:00.000Z",
      "iso_end": "2026-02-06T11:30:00.000Z"
    },
    {
      "date": "2026-02-06",
      "start": "15:00",
      "end": "15:30",
      "iso_start": "2026-02-06T13:00:00.000Z",
      "iso_end": "2026-02-06T13:30:00.000Z"
    }
  ]
}

Response Fields

slots[].date(string)Date of the slot (YYYY-MM-DD)
slots[].start(string)Start time in local timezone (HH:MM)
slots[].end(string)End time in local timezone (HH:MM)
slots[].iso_start(string)Start time in ISO 8601 UTC
slots[].iso_end(string)End time in ISO 8601 UTC

Calendar Events

GET/events

List calendar events for a date range

Query Parameters

start(string)requiredStart date (YYYY-MM-DD)
end(string)requiredEnd date (YYYY-MM-DD), max 30 days from start
include_all_day(boolean)Include all-day events (default: true)

Request

curl "https://intervals.so/api/v1/events?start=2026-02-06&end=2026-02-06" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "timezone": "Europe/Tallinn",
  "date_range": { "start": "2026-02-06", "end": "2026-02-06" },
  "total_events": 2,
  "events": [
    {
      "id": "abc123xyz",
      "title": "Team Standup",
      "start": "2026-02-06T09:00:00+02:00",
      "end": "2026-02-06T09:30:00+02:00",
      "all_day": false,
      "description": "Daily sync",
      "attendees": ["alice@example.com", "bob@example.com"],
      "meet_link": "https://meet.google.com/abc-def-ghi",
      "status": "confirmed",
      "is_recurring": true,
      "is_intervals_event": false
    }
  ]
}

Response Fields

events[].id(string)Unique event ID (use for PATCH/DELETE)
events[].title(string)Event title
events[].start(string)Start time (ISO 8601 with timezone)
events[].end(string)End time (ISO 8601 with timezone)
events[].all_day(boolean)Whether this is an all-day event
events[].attendees(string[])List of attendee emails
events[].meet_link(string | null)Google Meet link if present
events[].status(string)"confirmed", "tentative", or "cancelled"
events[].is_intervals_event(boolean)Whether created via Intervals
POST/events

Create a new calendar event

Request Body

title(string)requiredEvent title
start(string)requiredStart time (ISO 8601)
end(string)requiredEnd time (ISO 8601)
description(string)Event description
attendee_email(string)Guest email (adds Google Meet link)

Request

curl -X POST "https://intervals.so/api/v1/events" \
  -H "Authorization: Bearer ivl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Coffee Chat with Sarah",
    "start": "2026-02-07T14:00:00Z",
    "end": "2026-02-07T14:30:00Z",
    "attendee_email": "sarah@example.com"
  }'

Response

{
  "success": true,
  "event": {
    "id": "event123abc",
    "title": "Coffee Chat with Sarah",
    "start": "2026-02-07T14:00:00.000Z",
    "end": "2026-02-07T14:30:00.000Z",
    "meet_link": "https://meet.google.com/xyz-abc-123"
  }
}
PATCH/events/:id

Update an existing calendar event. Only provided fields are updated.

Request Body

title(string)New event title
start(string)New start time (ISO 8601)
end(string)New end time (ISO 8601)
description(string)New description

Request

curl -X PATCH "https://intervals.so/api/v1/events/abc123xyz" \
  -H "Authorization: Bearer ivl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Updated: Coffee Chat",
    "start": "2026-02-07T15:00:00Z",
    "end": "2026-02-07T15:30:00Z"
  }'

Response

{
  "success": true,
  "event": {
    "id": "abc123xyz",
    "title": "Updated: Coffee Chat",
    "start": "2026-02-07T15:00:00.000Z",
    "end": "2026-02-07T15:30:00.000Z"
  }
}

Errors

400At least one field must be provided
404Event not found
DELETE/events/:id

Cancel/delete a calendar event. Attendees are notified of cancellation.

Request

curl -X DELETE "https://intervals.so/api/v1/events/abc123xyz" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "success": true,
  "event_id": "abc123xyz",
  "message": "Event cancelled successfully"
}

Errors

404Event not found

Tasks

GET/tasks

List all tasks with optional filters

Query Parameters

status(string)"pending", "completed", or "dropped"
priority(string)"low", "medium", "high", or "urgent"
due_date(string)Filter by due date (YYYY-MM-DD)
limit(number)Max results (default: 50, max: 100)
offset(number)Pagination offset (default: 0)
sort(string)Sort field, prefix with - for desc (e.g., "-priority", "due_date")

Request

curl "https://intervals.so/api/v1/tasks?status=pending&priority=high" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "tasks": [
    {
      "id": "task-uuid-123",
      "title": "Ship API documentation",
      "description": "Complete API docs with examples",
      "status": "pending",
      "priority": "high",
      "due_date": "2026-02-06",
      "created_at": "2026-02-05T10:00:00Z",
      "completed_at": null
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0
}

Response Fields

tasks[].id(string)Unique task ID (UUID)
tasks[].title(string)Task title
tasks[].description(string | null)Task description
tasks[].status(string)"pending", "completed", or "dropped"
tasks[].priority(string)"low", "medium", "high", or "urgent"
tasks[].due_date(string | null)Due date (YYYY-MM-DD) or null
tasks[].completed_at(string | null)Completion timestamp or null
GET/tasks/today

Get today's tasks (due today + overdue + no due date)

Query Parameters

include_overdue(boolean)Include overdue tasks (default: true)

Request

curl "https://intervals.so/api/v1/tasks/today" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "date": "2026-02-06",
  "timezone": "Europe/Tallinn",
  "total": 3,
  "tasks": [...],
  "categorized": {
    "due_today": [...],
    "overdue": [...],
    "no_due_date": [...]
  }
}
POST/tasks

Create a new task

Request Body

title(string)requiredTask title
description(string)Task description
priority(string)"low", "medium" (default), "high", or "urgent"
due_date(string)Due date (YYYY-MM-DD)

Request

curl -X POST "https://intervals.so/api/v1/tasks" \
  -H "Authorization: Bearer ivl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Review pull request",
    "priority": "high",
    "due_date": "2026-02-06"
  }'

Response

{
  "task": {
    "id": "task-uuid-456",
    "title": "Review pull request",
    "description": null,
    "status": "pending",
    "priority": "high",
    "due_date": "2026-02-06",
    "created_at": "2026-02-06T10:00:00Z",
    "completed_at": null
  }
}
PATCH/tasks/:id

Update a task

Request Body

title(string)New title
description(string)New description
status(string)"pending", "completed", or "dropped"
priority(string)"low", "medium", "high", or "urgent"
due_date(string)Due date (YYYY-MM-DD) or null to clear

Request

curl -X PATCH "https://intervals.so/api/v1/tasks/task-uuid-456" \
  -H "Authorization: Bearer ivl_live_..." \
  -H "Content-Type: application/json" \
  -d '{"status": "completed"}'

Response

{
  "task": {
    "id": "task-uuid-456",
    "title": "Review pull request",
    "status": "completed",
    "completed_at": "2026-02-06T12:00:00Z",
    ...
  }
}
POST/tasks/:id/complete

Mark a task as completed (shortcut for PATCH with status=completed)

Request

curl -X POST "https://intervals.so/api/v1/tasks/task-uuid-456/complete" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "task": { ... },
  "message": "Task marked as completed"
}
DELETE/tasks/:id

Delete a task permanently

Request

curl -X DELETE "https://intervals.so/api/v1/tasks/task-uuid-456" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "success": true,
  "message": "Task deleted successfully"
}

Intervals (Availability Windows)

GET/intervals

List your availability intervals

Query Parameters

active_only(boolean)Only return active intervals (default: true)

Request

curl "https://intervals.so/api/v1/intervals" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "timezone": "Europe/Tallinn",
  "default_duration": 30,
  "total_intervals": 2,
  "intervals": [
    {
      "id": "interval-uuid-1",
      "title": "Weekday mornings",
      "time_range": "9:00 – 12:00",
      "is_active": true,
      "days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
      "start_time": "09:00",
      "end_time": "12:00"
    },
    {
      "id": "interval-uuid-2",
      "title": "Friday afternoon",
      "time_range": "14:00 – 17:00",
      "is_active": true,
      "days": ["friday"],
      "start_time": "14:00",
      "end_time": "17:00"
    }
  ]
}
POST/intervals

Create a new availability interval

Request Body

title(string)requiredName with day info (e.g., "Monday morning", "Weekday afternoons")
time_range(string)requiredTime range in "HH:MM – HH:MM" format

Request

curl -X POST "https://intervals.so/api/v1/intervals" \
  -H "Authorization: Bearer ivl_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Saturday morning",
    "time_range": "10:00 – 13:00"
  }'

Response

{
  "success": true,
  "interval": {
    "id": "interval-uuid-3",
    "title": "Saturday morning",
    "time_range": "10:00 – 13:00",
    "is_active": true
  }
}

Agent Discovery

For AI agent-to-agent meeting scheduling. See our IANP Protocol docs for full details.

GET/agent/discover

Discover a user for meeting negotiation

Query Parameters

key(string)Public agent key (ivl_pub_xxx) - preferred
username(string)Username - alternative to key

Request

curl "https://intervals.so/api/v1/agent/discover?key=ivl_pub_abc123" \
  -H "Authorization: Bearer ivl_live_..."

Response

{
  "found": true,
  "user": {
    "public_key": "ivl_pub_abc123",
    "username": "ruzgar",
    "display_name": "Ruzgar"
  },
  "negotiation_endpoint": "https://intervals.so/api/v1/agent-negotiation",
  "protocol": {
    "name": "IANP",
    "version": "1.0"
  }
}

Need help with the API?

hello@intervals.so