Skip to content

Latest commit

 

History

History
924 lines (722 loc) · 16 KB

File metadata and controls

924 lines (722 loc) · 16 KB

API Reference

Complete reference for TimelyOne API endpoints.


Table of Contents

  1. Authentication
  2. Setup API
  3. User API
  4. Calendar API
  5. Booking Link API
  6. Error Handling
  7. Response Formats

Authentication

TimelyOne uses cookie-based authentication with optional password protection.

Authentication Flow

1. User logs in → POST /api/auth/login
2. Server sets httpOnly cookie
3. Subsequent requests include cookie
4. Middleware validates session

Public Endpoints

These endpoints do NOT require authentication:

  • GET /book/[slug] - Public booking page
  • POST /api/booking-link/book - Create booking (public)
  • POST /api/auth/login - Login endpoint
  • GET /api/setup - Setup check (redirects if needed)

Protected Endpoints

All other endpoints require authentication. Unauthenticated requests receive:

  • Status: 401 Unauthorized
  • Redirect to /login for browser requests

Setup API

GET /api/setup

Check setup status and get current user.

Authentication: Public

Response (Setup Incomplete):

{
  "setupComplete": false,
  "user": null
}

Response (Setup Complete):

{
  "setupComplete": true,
  "user": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe",
    "timezone": "America/New_York"
  }
}

POST /api/setup

Complete first-time setup (creates user).

Authentication: Public

Request Body:

{
  "name": "John Doe",
  "email": "user@example.com",
  "timezone": "America/New_York",
  "password": "optional_password" // Optional
}

Response (Success):

{
  "success": true,
  "user": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe",
    "timezone": "America/New_York"
  }
}

Response (Error):

{
  "error": "User already exists"
}

Status Codes:

  • 200 - Success
  • 400 - Invalid request
  • 409 - User already exists

User API

GET /api/user

Get current user profile.

Authentication: Required

Response:

{
  "id": "user_123",
  "email": "user@example.com",
  "name": "John Doe",
  "timezone": "America/New_York",
  "password": true // Indicates if password is set
}

PATCH /api/user

Update user profile.

Authentication: Required

Request Body:

{
  "name": "Jane Doe",
  "timezone": "Europe/London"
}

Response:

{
  "success": true,
  "user": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "Jane Doe",
    "timezone": "Europe/London"
  }
}

POST /api/user/password

Set or update password.

Authentication: Required

Request Body (New Password):

{
  "newPassword": "new_secure_password"
}

Request Body (Change Password):

{
  "currentPassword": "old_password",
  "newPassword": "new_secure_password"
}

Response:

{
  "success": true,
  "message": "Password updated successfully"
}

Error Responses:

  • 401 - Current password incorrect
  • 400 - Invalid password format

DELETE /api/user

Delete user account and all data.

Authentication: Required

Response:

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

Note: This is a destructive operation that deletes:

  • User record
  • All calendar connections
  • All synced events
  • All booking links
  • All bookings

Authentication API

POST /api/auth/login

Login with email and password.

Authentication: Public

Request Body:

{
  "email": "user@example.com",
  "password": "user_password"
}

Response (Success):

{
  "success": true,
  "user": {
    "id": "user_123",
    "email": "user@example.com",
    "name": "John Doe"
  }
}

Response (Error):

{
  "error": "Invalid email or password"
}

Status Codes:

  • 200 - Success (sets httpOnly cookie)
  • 401 - Invalid credentials
  • 404 - User not found

POST /api/auth/logout

Logout and clear session.

Authentication: Required

Response:

{
  "success": true,
  "message": "Logged out successfully"
}

Calendar API

Calendar Connections

GET /api/calendar/connections

Get all connected calendar accounts.

Authentication: Required

Query Parameters:

  • userId (required): User ID

Response:

{
  "connections": [
    {
      "id": "conn_123",
      "provider": "google",
      "email": "user@gmail.com",
      "status": "ACTIVE",
      "connectedAt": "2024-01-01T00:00:00Z",
      "lastSyncAt": "2024-01-15T12:00:00Z",
      "calendars": [
        {
          "id": "cal_456",
          "name": "user@gmail.com",
          "isSelected": true,
          "color": "#3b82f6",
          "eventCount": 42
        }
      ]
    }
  ]
}

POST /api/calendar/connect

Initiate calendar connection (OAuth).

Authentication: Required

Request Body:

{
  "provider": "google" // or "microsoft"
}

Response:

{
  "redirectUrl": "https://oauth.composio.dev/..."
}

Usage: Open redirectUrl in new window for OAuth flow.

POST /api/calendar/disconnect

Disconnect a calendar account.

Authentication: Required

Request Body:

{
  "connectionId": "conn_123",
  "force": false // Optional: skip confirmation
}

Response (Has Booking Links):

{
  "error": "This calendar connection has active booking links",
  "requiresConfirmation": true,
  "affectedBookingLinks": [
    {
      "title": "Book a Meeting",
      "slug": "john-doe",
      "isActive": true,
      "url": "/book/john-doe"
    }
  ],
  "message": "Disconnecting will affect 1 booking link(s)..."
}

Response (Success):

{
  "success": true,
  "message": "Connection disconnected successfully"
}

Status Codes:

  • 200 - Success
  • 409 - Booking links conflict (requires force=true)
  • 404 - Connection not found

Calendar Sync

POST /api/calendar/sync

Sync events from connected calendars.

Authentication: Required

Request Body:

{
  "userId": "user_123",
  "forceFullSync": false // Optional: ignore sync tokens
}

Response:

{
  "success": true,
  "totalCreated": 5,
  "totalUpdated": 12,
  "totalDeleted": 2,
  "connectionResults": [
    {
      "connectionId": "conn_123",
      "email": "user@gmail.com",
      "created": 3,
      "updated": 8,
      "deleted": 1
    }
  ]
}

GET /api/calendar/callback

OAuth callback handler (called by Composio after authorization).

Authentication: Required

Query Parameters:

  • Handled automatically by OAuth flow

Response: Redirects to /connections

Event Management

GET /api/calendar/events

Get all calendar events.

Authentication: Required

Query Parameters:

  • userId (required): User ID
  • start (optional): Start date filter (ISO 8601)
  • end (optional): End date filter (ISO 8601)

Response:

{
  "events": [
    {
      "id": "event_123",
      "title": "Team Meeting",
      "description": "Weekly standup",
      "location": "Conference Room A",
      "startTime": "2024-01-15T10:00:00Z",
      "endTime": "2024-01-15T11:00:00Z",
      "isAllDay": false,
      "meetLink": "https://meet.google.com/abc-defg-hij",
      "calendarId": "cal_456",
      "calendarName": "user@gmail.com",
      "calendarColor": "#3b82f6",
      "attendees": ["attendee@example.com"],
      "status": "confirmed"
    }
  ]
}

POST /api/calendar/events

Create a new calendar event.

Authentication: Required

Request Body:

{
  "calendarId": "cal_456",
  "title": "New Meeting",
  "description": "Meeting description",
  "location": "Office",
  "startTime": "2024-01-20T14:00:00Z",
  "endTime": "2024-01-20T15:00:00Z",
  "isAllDay": false,
  "addGoogleMeet": true,
  "attendees": ["guest@example.com"]
}

Response:

{
  "success": true,
  "event": {
    "id": "event_789",
    "title": "New Meeting",
    "meetLink": "https://meet.google.com/xyz-abcd-efg",
    // ... other event fields
  }
}

Status Codes:

  • 200 - Success
  • 400 - Invalid request
  • 404 - Calendar not found

PATCH /api/calendar/events/[eventId]

Update an existing event.

Authentication: Required

Request Body:

{
  "title": "Updated Title",
  "startTime": "2024-01-20T15:00:00Z",
  "endTime": "2024-01-20T16:00:00Z"
}

Response:

{
  "success": true,
  "event": {
    "id": "event_789",
    // ... updated fields
  }
}

DELETE /api/calendar/events/[eventId]

Delete an event.

Authentication: Required

Response:

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

Calendar Management

PATCH /api/calendar/calendars/[calendarId]

Update calendar settings (e.g., toggle sync).

Authentication: Required

Request Body:

{
  "isSelected": true // Enable/disable sync for this calendar
}

Response:

{
  "success": true,
  "calendar": {
    "id": "cal_456",
    "name": "user@gmail.com",
    "isSelected": true
  }
}

Booking Link API

GET /api/booking-link

Get user's booking link configuration.

Authentication: Required

Query Parameters:

  • userId (required): User ID

Response:

{
  "bookingLink": {
    "id": "booking_123",
    "slug": "john-doe",
    "title": "Book a Meeting with John",
    "description": "Select a time that works for you",
    "calendarId": "cal_456",
    "isActive": true,
    "durations": [15, 30, 60],
    "defaultDuration": 30,
    "bufferTime": 10,
    "timezone": "America/New_York",
    "workingHours": {
      "monday": { "start": "09:00", "end": "17:00" },
      "tuesday": { "start": "09:00", "end": "17:00" },
      // ... other days
    }
  }
}

POST /api/booking-link

Create or update booking link.

Authentication: Required

Request Body:

{
  "slug": "john-doe",
  "title": "Book a Meeting with John",
  "description": "Select a time that works for you",
  "calendarId": "cal_456",
  "isActive": true,
  "durations": [15, 30, 60],
  "defaultDuration": 30,
  "bufferTime": 10,
  "timezone": "America/New_York",
  "workingHours": {
    "monday": { "start": "09:00", "end": "17:00" },
    "tuesday": { "start": "09:00", "end": "17:00" }
  }
}

Response:

{
  "success": true,
  "bookingLink": {
    "id": "booking_123",
    "slug": "john-doe",
    // ... other fields
  }
}

Status Codes:

  • 200 - Success (created or updated)
  • 400 - Invalid request
  • 409 - Slug already taken

GET /api/booking-link/availability

Get available time slots for booking.

Authentication: Public

Query Parameters:

  • slug (required): Booking link slug
  • date (required): Date to check (YYYY-MM-DD)
  • duration (required): Meeting duration in minutes

Response:

{
  "availableSlots": [
    {
      "start": "2024-01-20T09:00:00Z",
      "end": "2024-01-20T09:30:00Z"
    },
    {
      "start": "2024-01-20T10:00:00Z",
      "end": "2024-01-20T10:30:00Z"
    }
  ],
  "timezone": "America/New_York"
}

POST /api/booking-link/book

Create a new booking (public endpoint).

Authentication: Public

Request Body:

{
  "slug": "john-doe",
  "guestName": "Jane Smith",
  "guestEmail": "jane@example.com",
  "guestNotes": "Looking forward to discussing the project",
  "startTime": "2024-01-20T10:00:00Z",
  "duration": 30
}

Response:

{
  "success": true,
  "booking": {
    "id": "booking_456",
    "startTime": "2024-01-20T10:00:00Z",
    "endTime": "2024-01-20T10:30:00Z",
    "meetLink": "https://meet.google.com/abc-defg-hij",
    "guestName": "Jane Smith",
    "guestEmail": "jane@example.com"
  },
  "message": "Booking confirmed! Check your email for details."
}

Status Codes:

  • 200 - Success
  • 400 - Invalid request
  • 404 - Booking link not found
  • 409 - Time slot unavailable (conflict)

Error Handling

Error Response Format

All errors follow this format:

{
  "error": "Error message",
  "details": "Additional context (optional)"
}

Common HTTP Status Codes

  • 200 - Success
  • 400 - Bad Request (invalid input)
  • 401 - Unauthorized (authentication required)
  • 403 - Forbidden (insufficient permissions)
  • 404 - Not Found (resource doesn't exist)
  • 409 - Conflict (e.g., duplicate slug, time conflict)
  • 500 - Internal Server Error

Error Examples

Missing Required Field:

{
  "error": "Missing required field: title"
}

Invalid Format:

{
  "error": "Invalid date format",
  "details": "Expected ISO 8601 format"
}

Database Error:

{
  "error": "Failed to create event",
  "details": "Database connection error"
}

Response Formats

Success Response

{
  "success": true,
  "data": { /* resource data */ },
  "message": "Optional success message"
}

List Response

{
  "items": [ /* array of resources */ ],
  "total": 42,
  "page": 1,
  "pageSize": 20
}

Pagination

Not currently implemented. All list endpoints return full results.

Date/Time Format

All dates and times use ISO 8601 format:

2024-01-15T10:30:00Z        # UTC
2024-01-15T10:30:00-05:00   # With timezone offset

Timezone Handling

  • Dates stored in UTC in database
  • API accepts ISO 8601 with timezone
  • Responses include timezone information
  • Booking API converts to user's timezone

Rate Limiting

Currently not implemented. For self-hosted single-user application, rate limiting is typically handled at reverse proxy level.


Webhooks

Not currently implemented. Future feature for real-time sync.


Best Practices

API Usage

  1. Always handle errors: Check for error responses
  2. Validate input: Check required fields before sending
  3. Use ISO 8601: For all date/time values
  4. Include timezone: Explicitly specify timezone when creating events
  5. Check sync status: Before displaying calendar data

Security

  1. HTTPS only: Use HTTPS in production
  2. Validate cookies: Don't manipulate auth cookies
  3. Sanitize input: Escape user input on frontend
  4. Rate limit: Implement at reverse proxy level
  5. CORS: Configure appropriately for your domain

Performance

  1. Cache responses: Cache calendar data on frontend
  2. Batch requests: Combine multiple operations when possible
  3. Use incremental sync: Prefer forceFullSync: false
  4. Optimize queries: Filter by date range when possible

Examples

Complete Booking Flow

// 1. Get available slots
const slots = await fetch(
  `/api/booking-link/availability?slug=john-doe&date=2024-01-20&duration=30`
)
const { availableSlots } = await slots.json()

// 2. Create booking
const booking = await fetch('/api/booking-link/book', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    slug: 'john-doe',
    guestName: 'Jane Smith',
    guestEmail: 'jane@example.com',
    startTime: availableSlots[0].start,
    duration: 30
  })
})

const result = await booking.json()
console.log(result.booking.meetLink)

Create Event with Google Meet

const event = await fetch('/api/calendar/events', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    calendarId: 'cal_456',
    title: 'Team Sync',
    startTime: '2024-01-20T14:00:00Z',
    endTime: '2024-01-20T15:00:00Z',
    addGoogleMeet: true,
    attendees: ['team@example.com']
  })
})

const { event: createdEvent } = await event.json()
console.log(createdEvent.meetLink)

Changelog

Version 1.0.0 (Current)

  • Initial API release
  • Calendar connection management
  • Event CRUD operations
  • Booking link system
  • Authentication system

Planned Features

  • Webhook support for real-time updates
  • Batch event operations
  • Recurring event management API
  • Email notification triggers
  • Calendar export (ICS format)

For implementation details, see ARCHITECTURE.md.

For troubleshooting, see TROUBLESHOOTING.md.