CSpace REST API Documentation
[TOC]
Base URL
Base URL: /api/v1
Authentication
Uses JWT (JSON Web Tokens) via djangorestframework-simplejwt.
Include the access token in requests: Authorization: Bearer <access_token>
Obtain Token (Login)
POST /api/v1/auth/token/
Request Body:
{
"username": "john_doe",
"password": "secretpassword"
}
Response: 200 OK
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
Response Cookie:
Set-Cookie: refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...; HttpOnly; Path=/api/v1/auth/; SameSite=Lax; Secure
Note: The refresh token is stored in an HttpOnly cookie and is not accessible via JavaScript. The
Secureflag is set in production only.
Refresh Token
POST /api/v1/auth/token/refresh/
Request Cookie: refresh_token (HttpOnly cookie set during login)
Response: 200 OK
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
}
Note: In production, the refresh token is rotated and a new
refresh_tokencookie is set. In development, the refresh token is not rotated.
Logout
POST /api/v1/auth/logout/
Request Cookie: refresh_token (HttpOnly cookie set during login)
Request Header: Authorization: Bearer <access_token>
Response: 205 Reset Content
Note: The refresh token is blacklisted and the
refresh_tokencookie is cleared.
Users
Get all users from User
GET /api/v1/users/
Required Permission: cspace group
Response:
{
"results": [
{
"id": 1,
"username": "ta217",
"display_name": "TA 217"
},
{
"id": 2,
"username": "johndoe",
"display_name": "John Doe"
},
...
]
}
Get User info
GET /api/v1/users/me/
Required Permission: logged in users
Response:
{
"id": ,
"username": "",
"display_name": ""
}
Get User’s Groups (user_groups)
GET /api/v1/users/me/user-groups/
Required Permission: logged in users
Response: 200 OK
{
"results": [
{
"id": 1,
"name": "cspace",
"permissions": "admin"
},
{
"id": 2,
"name": "522",
"permissions": "member"
},
...
]
}
id is group_id
Notifications
List All Notifications (NEW)
GET /api/v1/notifications/
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
string |
Filter by status: |
|
int |
Page number |
Response: 200 OK
{
"count": 25,
"next": "/api/v1/notifications/?page=2",
"previous": null,
"results": [
{
"id": 1,
"description": "Your room registration has been approved.",
"status": "unread",
"created_at": "2026-01-20T10:30:00Z"
}
]
}
Refresh Notifications
Currently done by polling every 10 seconds, replace with websocket?
Mark Notification as Viewed
PATCH /api/v1/notifications/{id}/
Request Body:
{
"status": "read"
}
Response: 200 OK
{
"id": 1,
"status": "read"
}
Archive Notification
PATCH /api/v1/notifications/{id}/
Request Body:
{
"status": "archived"
}
Response: 200 OK
{
"id": 1,
"status": "archived"
}
Groups
List all groups
GET /api/v1/groups/
Required Permission: cspace group
Response: 200 OK
{
"results": [
{
"id": 1,
"name": "cspace",
},
{
"id": 2,
"name": "522",
}
]
}
Get own group’s group details (Admin or member)
GET /api/v1/groups/{id}/
Required Permissions: cspace group or own group
Response: 200 OK
{
"results": [
{
"user_group_id": 1,
"user_id": 1,
"username": "ta217",
"permissions": "admin",
},
{
"user_group_id": 2,
"user_id": 2,
"username": "johndoe",
"permissions": "member",
}
]
}
Create group (Admin)
POST /api/v1/groups/
Required Permission: cspace group
Request Body:
{
"name": "research-team",
}
Response: 201 Created
{
"id": 3,
"name": "research-team",
}
Delete group (Admin)
DELETE /api/v1/groups/{id}/
Required Permission: cspace group
Response: 204 No Content
Add User to Group
POST /api/v1/groups/{id}/user-groups/
Request Body:
{
"username": "user1",
"permissions": "member"
}
Response: 201 Created
{
"user_group_id": 15,
"username": "",
"group_id": 1
}
User Groups
List all users from all groups (list all user_groups)
GET /api/v1/user-groups/
Required Permissions: cspace group
Response: 200 OK
{
"results": [
{
"user_group_id": 1,
"group_id": 1,
"user_id": 1,
"username": "ta217",
"permissions": "admin",
},
{
"user_group_id": 2,
"group_id": 1,
"user_id": 2,
"username": "johndoe",
"permissions": "member",
},
{
"user_group_id": 3,
"group_id": 2,
"user_id": 1,
"username": "ta217",
"permissions": "admin",
},
{
"user_group_id": 4,
"group_id": 2,
"user_id": 3,
"username": "hsinmu",
"permissions": "member",
}
]
}
Get user_group
GET /api/v1/user-groups/{id}/
Required Permissions: cspace group or own group
Response: 200 OK
{
"id": ,
"username": "",
"permissions": "",
"group": {
"id": 1,
"name": ""
}
}
Update a user_group
PUT /api/v1/user-groups/{id}/
Required Permission: cspace group or admin permission of own group
Request Body:
{
"permissions": ""
}
Response: 200 OK
Delete User from Group
DELETE /api/v1/user-groups/{id}/
Required Permission: cspace group or admin permission of own group
Response: 204 No Content
Classrooms
List All Classrooms
GET /api/v1/classrooms/
(Grouped by floor, ordered by name)
Response: 200 OK
{
"results": [
{
"id": 1,
"name": "Room A",
"capacity": 30,
"floor": 2,
"equipment": {"projector":1,"projection_screen":1,"whiteboard":3,"chair":23,"svg":{"x":12,"y":345,"width":93,"height":110,"text":"321\n319","type":"discuss"}}
}
]
}
Get Classroom Details
GET /api/v1/classrooms/{name}/
Response: 200 OK
{
"id": 1,
"name": "Room A",
"capacity": 30,
"floor": 2,
"equipment": {"projector":1,"projection_screen":1,"whiteboard":3,"chair":23,"svg":{"x":12,"y":345,"width":93,"height":110,"text":"321\n319","type":"discuss"}}
}
Create Classroom (Admin)
POST /api/v1/classrooms/
Required Permission: cspace group
Request Body:
{
"name": "Room B",
"capacity": 50,
"floor": 3,
"equipment": {"projector":1,"projection_screen":1,"whiteboard":3,"chair":23,"svg":{"x":12,"y":345,"width":93,"height":110,"text":"321\n319","type":"discuss"}}
}
Response: 201 Created
Update Classroom (Admin)
PUT /api/v1/classrooms/{name}/
Required Permission: cspace group
Request Body:
{
"capacity": 55,
"equipment": {"projector":1,"projection_screen":1,"whiteboard":3,"chair":23,"svg":{"x":12,"y":345,"width":93,"height":110,"text":"321\n319","type":"discuss"}}
}
Response: 200 OK
Registrations
Single room reservation management.
Create Registration
Required Permission: belongs to any group
POST /api/v1/registrations/
Request Body:
{
"classroom": "Room A",
"group_id": 1,
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"description": "Team meeting"
}
Response: 201 Created (does not need approval)
{
"id": 100,
"classroom": "Room A",
"group_id": 1,
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"description": "Team meeting",
"status": "pending",
"created_by": "john_doe",
"created_at": "2026-01-22T09:00:00Z"
}
Get Registration Details
GET /api/v1/registrations/{id}/
Required Permission: cspace group or registration creator
Response: 200 OK
{
"id": 100,
"classroom": "Room A",
"reserved_group": "522",
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"description": "Team meeting",
"status": "pending",
"created_by": "john_doe",
"created_at": "2026-01-22T09:00:00Z"
}
Update Registration
PUT /api/v1/registrations/{id}/
Required Permission: cspace group or registration creator
Request Body:
{
"classroom": "Room A",
"group_id": 1,
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"description": "Team meeting"
}
Response: 200 OK
Delete Registration
DELETE /api/v1/registrations/{id}/
Required Permission: cspace group or registration creator
Response: 204 No Content
List User’s Registrations
GET /api/v1/users/me/registrations/
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
string |
Filter: |
|
int |
Number of results |
Response: 200 OK
{
"results": [
{
"id": 100,
"reserved_group": "522",
"classroom": "Room A",
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"status": "approved",
"description": "Team meeting"
}
]
}
Get Room Agenda
GET /api/v1/classrooms/{name}/agenda/
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
date |
Start of date range |
|
date |
End of date range |
Response: 200 OK
{
"classroom": "Room A",
"registrations": [
{
"id": 100,
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"status": "approved",
"reserved_by": "呂學一",
"reserved_group": "522",
"description": "Team meeting"
}
]
}
Check Room Availability
GET /api/v1/classrooms/{name}/availability/
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
date |
Date to check |
|
time |
Start time |
|
time |
End time |
Response: 200 OK
{
"classroom": "Room A",
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"is_available": false,
"conflicts": [
{
"id": 99,
"start_time": "09:00",
"end_time": "11:00"
}
]
}
List Registrations (Admin)
GET /api/v1/registrations/
Required Permission: cspace group
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
string |
Filter: |
Response: 200 OK
{
"registrations": [
{
"id": 100,
"classroom": "102",
"date": "2026-02-01",
"start_time": "10:00",
"end_time": "12:00",
"reserved_by": " 呂學一",
"reserved_group": "522",
"description": "Team meeting",
"status": "pending"
},
{
"id": 101,
"classroom": "101",
"date": "2026-02-02",
"start_time": "10:00",
"end_time": "12:00",
"reserved_by": "蔡欣穆",
"reserved_group": "316",
"description": "Team meeting",
"status": "pending"
}
]
}
Approve Registration (Admin)
POST /api/v1/registrations/{id}/approve/
Required Permission: cspace group
Response: 200 OK
Reject Registration (Admin)
POST /api/v1/registrations/{id}/reject/
Required Permission: cspace group
Response: 200 OK
Allocation Events
Long-term room allocation through draw/lottery system.
List Allocation Events
GET /api/v1/allocation-events/
Required Permission: logged in users
Response: 200 OK
{
"results": [
{
"id": 1,
"status": "open",
"registration_start": "2026-01-15T00:00:00Z",
"registration_end": "2026-01-30T23:59:59Z"
}
]
}
Get Allocation Event Details
GET /api/v1/allocation-events/{id}/
Required Permission: logged in users
Response: 200 OK
{
"id": 1,
"status": "open",
"registration_start": "2026-01-15T00:00:00Z",
"registration_end": "2026-01-30T23:59:59Z",
"target_start_date": "2026-02-22",
"target_end_date": "2026-06-12"
}
Create Allocation Event (Admin)
POST /api/v1/allocation-events/
Required Permission: cspace group
Request Body:
{
"registration_start": "2026-01-15T00:00:00Z",
"registration_end": "2026-01-30T23:59:59Z",
"target_start_date": "2026-02-22",
"target_end_date": "2026-06-12"
}
Response: 201 Created
End Allocation Event (Admin)
POST /api/v1/allocation-events/{id}/end/
Required Permission: cspace group
Response: 200 OK
Distribute Allocations (Admin)
POST /api/v1/allocation-events/{id}/distribute/
Required Permission: cspace group
Response: 200 OK
{
"id": 1,
"total_registrations": 50,
"successful_allocations": 45,
"failed_allocations": 5
}
Get Room Agenda for Event
GET /api/v1/allocation-events/{id}/room-agenda/
Required Permission: cspace group
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
string |
Classroom name |
Response: 200 OK
{
"classroom": "Room A",
"registrations": [
{
"id": 100,
"is_pending": true,
"start_time": "12:00",
"end_time": "14:00",
"day_of_week": 3,
"reserved_by": "呂學一",
"reserved_group": "522",
"description": "Team meeting"
}
]
}
start_time or end_time do not need to be the start or end of a period.
Sunday is the first day of the week, so a registration for Monday should have day_of_week set to 2.
Allocation Registrations (User’s draw entries)
For registrations below, start_time or end_time do not need to be the start or end of a period.
Sunday is the first day of the week, so a registration for Monday should have day_of_week set to 2.
Register for Allocation Event
POST /api/v1/allocation-events/{event_id}/registrations/
Required Permission: belongs to any group
Request Body:
{
"group_id": 2,
"classroom": "Room A",
"start_time": "9:10",
"end_time": "10:20",
"day_of_week": 3,
"description": "Research project meetings"
}
Response: 201 Created
List User’s Allocation Registrations
GET /api/v1/allocation-events/{event_id}/registrations/
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
string |
Filter by username (admin only) |
|
string |
Filter: |
Response: 200 OK
{
"registrations": [
{
"id": 200,
"is_pending": true,
"classroom": "Room A",
"start_time": "14:20",
"end_time": "18:20",
"day_of_week": 3,
"reserved_group": "522",
"description": "Research project meetings"
}
]
}
Get Allocation Registration Result
GET /api/v1/allocation-events/{event_id}/registrations/{id}/
Response: 200 OK
{
"id": 200,
"event_id": 1,
"classroom": "Room A",
"start_time": "7:10",
"end_time": "22:00",
"day_of_week": 3,
"reserved_group": "522",
"status": "approved"
}
Update Allocation Registration
PUT /api/v1/allocation-events/{event_id}/registrations/{id}/
Required Permission: cspace group or own group
Request Body:
{
"classroom": "Room A",
"group_id": 2,
"start_time": "3:00",
"end_time": "4:00",
"day_of_week": 3,
"description": "Updated description"
}
Response: 200 OK
Delete Allocation Registration
DELETE /api/v1/allocation-events/{event_id}/registrations/{id}/
Response: 204 No Content
Approve Allocation Registration (Admin)
POST /api/v1/allocation-events/{event_id}/registrations/{id}/approve/
Required Permission: cspace group
Response: 200 OK
Reject Allocation Registration (Admin)
POST /api/v1/allocation-events/{event_id}/registrations/{id}/reject/
Required Permission: cspace group
Response: 200 OK
Batch Allocation (Long-term Registrations)
To allocate, delete, modify, and list long-term registration events.
TODO: complete this.
Logs
List Change Logs (Admin)
GET /api/v1/logs/
Required Permission: cspace group
Query Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
int |
Page number |
|
int |
Items per page |
|
string |
Filter by action type |
|
string |
Filter by username |
Response: 200 OK
{
"count": 500,
"next": "/api/v1/logs/?page=2",
"previous": null,
"results": [
{
"id": 1,
"action": "registration.approved",
"user": "admin_user",
"target": "registration:100",
"details": {
"classroom": "Room A",
"date": "2026-02-01"
},
"created_at": "2026-01-22T10:00:00Z"
}
]
}
Error Responses
All endpoints return consistent error responses:
400 Bad Request
{
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": {
"start_time": ["Start time must be before end time"],
"date": ["Date cannot be in the past"]
}
}
403 Forbidden
{
"error": "You do not have permission to perform this action",
"code": "PERMISSION_DENIED"
}
404 Not Found
{
"error": "Registration not found",
"code": "NOT_FOUND"
}
409 Conflict
{
"error": "Room is already booked for the requested time",
"code": "CONFLICT",
"details": {
"existing_registration_id": 99
}
}