Reservations API
Listing, viewing and cancelling confirmed interviews. See API Conventions for shared rules.
Base path: /api/v1/projects/{projectId}/reservations
| Method | Path | Summary | Role |
|---|---|---|---|
| GET | / |
List reservations | viewer |
| GET | /{reservationId} |
Get reservation detail | viewer |
| PATCH | /{reservationId}/cancel |
Cancel a reservation | member |
All endpoints require Authorization: Bearer <access_token>; PATCH / PUT / DELETE require member or above.
Reservations are not created through this router
A reservation comes into being through schedule confirmation: the candidate calls POST /api/v1/scheduling/{token}/submit-availability, then an admin calls POST /api/v1/projects/{id}/candidates/{cid}/confirm-schedule.
The Reservation Object
| Field | Type | Description |
|---|---|---|
id |
integer | Reservation ID |
projectId |
integer | Project ID |
projectCandidateId |
integer | Project candidate ID |
interviewerId |
integer | Assigned interviewer's user ID |
scheduledAt |
string(date-time) | Interview start time |
durationMinutes |
integer | Duration in minutes |
interviewType |
enum | online_meet / online_zoom / offline / any |
meetingUrl |
string | null | Meeting URL |
status |
enum | confirmed / cancelled |
candidate |
object | Candidate details (id / externalUserId / email / phone / name) |
interviewer |
object | Interviewer details (User) |
createdAt / updatedAt |
string(date-time) | Creation / update timestamps |
List Reservations
URI
Query Parameters
| Field | Type | Required | Default | Rules | Description |
|---|---|---|---|---|---|
page |
integer | - | 1 |
Positive integer | Page number |
limit |
integer | - | 20 |
1โ100 | Items per page |
sort |
string | - | - | - | Sort order |
status |
enum | - | - | confirmed / cancelled |
Filter by status |
startDate |
string | - | - | YYYY-MM-DD |
Reservations on or after this date |
endDate |
string | - | - | YYYY-MM-DD |
Reservations on or before this date |
Example Request
Response (200 OK)
data is an array of Reservation, with pagination.
{
"success": true,
"status": "success",
"statusCode": 200,
"data": [
{
"id": 7,
"projectId": 1,
"projectCandidateId": 12,
"interviewerId": 5,
"scheduledAt": "2026-02-03T01:00:00Z",
"durationMinutes": 60,
"interviewType": "online_meet",
"meetingUrl": "https://meet.google.com/xxx-yyyy-zzz",
"status": "confirmed",
"candidate": {
"id": 100,
"externalUserId": "1001",
"email": "yamada@example.com",
"phone": "090-1234-5678",
"name": "Taro Yamada"
},
"interviewer": {
"id": 5,
"email": "interviewer@example.com",
"name": "Suenari",
"picture": null,
"role": "member",
"createdAt": "2026-01-10T09:00:00Z"
},
"createdAt": "2026-01-20T09:00:00Z",
"updatedAt": "2026-01-20T09:00:00Z"
}
],
"pagination": { "page": 1, "limit": 20, "totalCount": 8, "totalPages": 1, "hasNext": false, "hasPrevious": false },
"path": "/api/v1/projects/1/reservations",
"method": "GET"
}
Errors
| Description | Status code | Status name |
|---|---|---|
| Malformed query | 400 | Bad Request |
| Token missing or invalid | 401 | Unauthorized |
| Project does not exist | 404 | Not Found |
| Server internal error | 500 | Internal Server Error |
Get Reservation Detail
URI
Path Parameters
| Field | Rules |
|---|---|
projectId |
Required positive integer |
reservationId |
Required positive integer |
Response (200 OK)
data holds a Reservation.
Errors
| Description | Status code | Status name |
|---|---|---|
| Token missing or invalid | 401 | Unauthorized |
| Reservation does not exist | 404 | Not Found |
| Server internal error | 500 | Internal Server Error |
Cancel Reservation
The row is not deleted; status is updated to cancelled.
URI
Request
No body.
Response (200 OK)
data holds the cancelled Reservation (with status set to cancelled).
Errors
| Description | Status code | Status name |
|---|---|---|
| Token missing or invalid | 401 | Unauthorized |
| Insufficient role | 403 | Forbidden |
| Reservation does not exist | 404 | Not Found |
| Google Calendar error | 502 | Bad Gateway |
Side Effects
- The confirmed Google Calendar event is cancelled
- The candidate's status may transition to
cancelled(allowed fromscheduledandinterviewed)
PROTOTYPE_MODE
While PROTOTYPE_MODE=true, calendar operations and emails are skipped and only the DB is updated.
Re-confirming afterwards
reservations.project_candidate_id is UNIQUE, so creating a new reservation for a candidate who still has a cancelled one requires care with the existing row.