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 Secure flag 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_token cookie 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_token cookie 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

status

string

Filter by status: unread, read, archived

page

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

status

string

Filter: upcoming, past, all

limit

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

start_date

date

Start of date range

end_date

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

Date to check

start_time

time

Start time

end_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

status

string

Filter: pending, approved

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 Unavailable Dates for Event

GET /api/v1/allocation-events/{id}/unavailable-dates/

Query Parameters:

Parameter

Type

Description

classroom

string

Classroom name

start_date

date

Start of range

end_date

date

End of range

Response: 200 OK

{
  "classroom": "Room A",
  "unavailable_dates": [
    "2026-02-05",
    "2026-02-06"
  ]
}

Get Room Agenda for Event

GET /api/v1/allocation-events/{id}/room-agenda/

Required Permission: cspace group

Query Parameters:

Parameter

Type

Description

classroom

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

user

string

Filter by username (admin only)

status

string

Filter: pending, approved

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

page

int

Page number

per_page

int

Items per page

action

string

Filter by action type

user

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"]
  }
}

401 Unauthorized

{
  "error": "Authentication credentials were not provided",
  "code": "NOT_AUTHENTICATED"
}

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
  }
}