API Documentation: Get Organization Appointments
Endpoint
GET /api/v1/calendar/appointments
Description
Retrieves calendar appointments/events for an organization. Supports filtering by date range and user email. Returns only non-deleted, future appointments for active (non-archived) cases.
Authentication
Required Header:
cv-api-key(string, required): Organization API key for authentication and authorization
Query Parameters
| Parameter | Type | Required | Format | Description |
|---|---|---|---|---|
start_date | string | Conditional* | YYYY-MM-DD | Start date of the date range filter |
end_date | string | Conditional* | YYYY-MM-DD | End date of the date range filter |
user_email | string | Optional | Email format | Filter appointments by user email |
Validation Rules:
- If
start_dateis provided,end_datemust also be provided (and vice versa) - If
user_emailis not provided, bothstart_dateandend_dateare required - If both dates are provided,
start_datemust be less than or equal toend_date - Date format must be
YYYY-MM-DD(e.g.,2024-01-15)
Rate Limiting
- Default: 500 requests per 60 seconds per organization
- On rate limit exceeded: Returns
429 Too Many Requestswith retry information
Request Example
curl -X GET "https://api.example.com/api/v1/calendar/appointments?start_date=2024-01-01&end_date=2024-01-31&user_email=user@example.com" \
-H "cv-api-key: your-api-key-here"
Response Format
Success Response (200 OK)
{
"status": 200,
"success": true,
"message": "Appointments fetched successfully",
"data": [
{
"id": "event-id",
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z",
"title": "Appointment Title",
"start": "2024-01-20T14:00:00Z",
"end": "2024-01-20T15:00:00Z",
"topic": "Meeting Topic",
"description": "Appointment description",
"color": "#FF5733",
"isEditable": true,
"agentEventId": "agent-event-id",
"agentName": "Agent Name",
"status": "CONFIRMED",
"isDeleted": false,
"meetingDetails": {
// Activity metadata object
},
"case": {
"id": "case-id",
"shortId": "CASE-123",
"status": "ACTIVE",
"title": "Case Title"
},
"submitter": {
"id": "user-id",
"firstName": "John",
"lastName": "Doe",
"email": "user@example.com"
}
}
]
}
Error Response (400 Bad Request)
{
"status": 400,
"success": false,
"message": "Invalid request",
"error": "Error message describing the validation or processing error"
}
Rate Limit Exceeded (429 Too Many Requests)
{
"status": 429,
"success": false,
"error": "Rate limit exceeded",
"message": "Maximum 500 requests per 60 seconds exceeded",
"retryAfter": 60
}
Behavior Details
-
Date Filtering:
start_dateis set to the start of day (00:00:00)end_dateis set to the end of day (23:59:59)- Matches events that overlap the range (start or end within range)
-
User Filtering:
- If
user_emailis provided, the system:- Looks up the user by email (case-insensitive)
- Returns
NotFoundErrorif user doesn't exist - Filters appointments to that user only
- If
-
Data Filtering:
- Only returns appointments where:
isDeleted = falseend >= current date(future appointments only)- Associated case is not archived (
isArchived = false) - Case belongs to the authenticated organization
- Only returns appointments where:
-
Sorting:
- Results are sorted by
endDateTimein ascending order (earliest end times first)
- Results are sorted by
-
Organization Context:
- Organization is determined from the
cv-api-keyheader - All returned appointments belong to that organization
- Organization is determined from the
Error Scenarios
| Error | Status Code | Description |
|---|---|---|
| Missing API Key | 400 | cv-api-key header is missing |
| Invalid API Key | 400 | API key is invalid or doesn't match an organization |
| Invalid Date Format | 400 | Date parameters don't match YYYY-MM-DD format |
| Missing Required Dates | 400 | When user_email is not provided, both dates are required |
| Incomplete Date Range | 400 | Only one of start_date or end_date provided |
| Invalid Date Range | 400 | start_date is after end_date |
| User Not Found | 400 | user_email provided but user doesn't exist in organization |
| Rate Limit Exceeded | 429 | Too many requests in the time window |
Notes
- The response includes case and submitter information for each appointment
- Empty results return an empty array
[]in thedatafield
Response Format
Success Response (200 OK)
{
"status": 200,
"success": true,
"message": "Appointments fetched successfully",
"data": [
{
"id": "event-id",
"createdAt": "2024-01-15T10:00:00Z",
"updatedAt": "2024-01-15T10:00:00Z",
"title": "Appointment Title",
"start": "2024-01-20T14:00:00Z",
"end": "2024-01-20T15:00:00Z",
"topic": "Meeting Topic",
"description": "Appointment description",
"color": "#FF5733",
"isEditable": true,
"agentEventId": "agent-event-id",
"agentName": "Agent Name",
"status": "CONFIRMED",
"isDeleted": false,
"meetingDetails": {
// Activity metadata object
},
"case": {
"id": "case-id",
"shortId": "CASE-123",
"status": "ACTIVE",
"title": "Case Title"
},
"submitter": {
"id": "user-id",
"firstName": "John",
"lastName": "Doe",
"email": "user@example.com"
}
}
]
}
Error Response (400 Bad Request)
{
"status": 400,
"success": false,
"message": "Invalid request",
"error": "Error message describing the validation or processing error"
}
Rate Limit Exceeded (429 Too Many Requests)
{
"status": 429,
"success": false,
"error": "Rate limit exceeded",
"message": "Maximum 500 requests per 60 seconds exceeded",
"retryAfter": 60
}