Appearance
Projects API
Projects are the top-level container for issues, sprints, epics, and board lanes.
Permissions
| Action | Required Permission | Scope |
|---|---|---|
| List | Projects: Read | Only projects accessible via team membership, accessAllProjects role flag, or ownership |
| View | Projects: Read | Must have project access |
| Create | Projects: Create | — |
| Update | Projects: Update (Own/All) | Must have project access |
| Delete | Projects: Delete (Own/All) | Must have project access |
| Transfer ownership | Owner or Admin | Must be project owner or admin |
| Upload / remove avatar | Projects: Update (Own/All) | Must have project access |
| Serve avatar | Projects: Read | Must have project access |
Admins bypass all permission checks. Project owners have full access to their own projects.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/projects | List all projects |
POST | /api/projects | Create a project |
GET | /api/projects/{id} | Get a project |
PUT | /api/projects/{id} | Update a project |
DELETE | /api/projects/{id} | Delete a project |
POST | /api/projects/{id}/avatar | Upload a project avatar |
GET | /api/projects/{id}/avatar/{variant} | Serve an avatar image (avif or webp) |
DELETE | /api/projects/{id}/avatar | Remove the project avatar |
POST | /api/projects/{id}/pin | Pin or unpin the project for the current user |
Create Project
POST /api/projects
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Project name, max 255 characters |
code | string | Yes | 2-5 uppercase letters (e.g., KD), must be unique |
description | string | Yes | Project description, max 5,000 characters |
user_id | integer | Yes | Project owner user ID |
team_ids | integer[] | Yes | Team IDs to grant access (can be empty []) |
direct_member_ids | integer[] | Yes | Individual user IDs to grant access (can be empty []) |
bash
curl -X POST https://{tenant}.kendo.dev/api/projects \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Website Redesign",
"code": "WEB",
"description": "Complete redesign of the public website with new branding.",
"user_id": 1,
"team_ids": [1],
"direct_member_ids": [4, 5]
}'json
{
"id": 3,
"name": "Website Redesign",
"code": "WEB",
"description": "Complete redesign of the public website with new branding.",
"user_id": 1,
"issue_ids": [],
"sprint_ids": [],
"epic_ids": [],
"lane_ids": [10, 11, 12, 13],
"team_ids": [1],
"direct_member_ids": [4, 5],
"created_at": "2026-03-13T10:30:00.000000Z",
"avatar": null
}Update Project
PUT /api/projects/{id}
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Project name, max 255 characters |
code | string | Yes | 2-5 uppercase letters, unique (except self) |
description | string | Yes | Max 5,000 characters |
user_id | integer | Yes | Project owner user ID |
lane_ids | integer[] | Yes | Ordered lane IDs (min 1, must belong to project) |
team_ids | integer[] | Yes | Team IDs (can be empty []) |
direct_member_ids | integer[] | Yes | Individual user IDs (can be empty []) |
bash
curl -X PUT https://{tenant}.kendo.dev/api/projects/3 \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"name": "Website Redesign",
"code": "WEB",
"description": "Complete redesign of the public website with new branding.",
"user_id": 1,
"lane_ids": [10, 11, 12, 13],
"team_ids": [1, 2],
"direct_member_ids": []
}'json
{
"id": 3,
"name": "Website Redesign",
"code": "WEB",
"description": "Complete redesign of the public website with new branding.",
"user_id": 1,
"issue_ids": [50, 51, 52],
"sprint_ids": [8],
"epic_ids": [3],
"lane_ids": [10, 11, 12, 13],
"team_ids": [1, 2],
"direct_member_ids": [],
"created_at": "2026-03-13T10:30:00.000000Z",
"avatar": null
}Delete Project
DELETE /api/projects/{id}
Returns 204 No Content on success.
bash
curl -X DELETE https://{tenant}.kendo.dev/api/projects/3 \
-H "Authorization: Bearer your-token"WARNING
Deleting a project removes all its issues, sprints, epics, lanes, and time entries. This action cannot be undone.
Project Avatar
A project can have an uploaded avatar image. On upload, the image is re-encoded into two optimised variants — AVIF and WebP — and its EXIF metadata is stripped. When a project has no avatar, the avatar field is null; clients should fall back to a generated placeholder.
The avatar field on the project resource is either null or an object of absolute URLs to the two variants:
json
"avatar": {
"avif": "https://{tenant}.kendo.dev/api/projects/3/avatar/avif?v=1ChqqBvEsCTjLG8G",
"webp": "https://{tenant}.kendo.dev/api/projects/3/avatar/webp?v=1ChqqBvEsCTjLG8G"
}The ?v= token changes on every upload, so cached images refresh automatically when the avatar is replaced.
Upload Avatar
POST /api/projects/{id}/avatar
Send the image as multipart/form-data. Requires Projects: Update.
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Image file — JPEG, PNG, WebP, or AVIF, max 10 MB |
Returns the updated project resource with the avatar field populated. Re-uploading replaces the previous image.
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/3/avatar \
-H "Authorization: Bearer your-token" \
-F "[email protected]"json
{
"id": 3,
"name": "Website Redesign",
"code": "WEB",
"description": "Complete redesign of the public website with new branding.",
"user_id": 1,
"issue_ids": [50, 51, 52],
"sprint_ids": [8],
"epic_ids": [3],
"lane_ids": [10, 11, 12, 13],
"team_ids": [1, 2],
"direct_member_ids": [],
"created_at": "2026-03-13T10:30:00.000000Z",
"avatar": {
"avif": "https://{tenant}.kendo.dev/api/projects/3/avatar/avif?v=1ChqqBvEsCTjLG8G",
"webp": "https://{tenant}.kendo.dev/api/projects/3/avatar/webp?v=1ChqqBvEsCTjLG8G"
}
}Serve Avatar
GET /api/projects/{id}/avatar/{variant}
Streams the raw image for the requested variant — avif or webp. Requires Projects: Read. Responses are privately cacheable.
bash
curl https://{tenant}.kendo.dev/api/projects/3/avatar/webp \
-H "Authorization: Bearer your-token" \
--output avatar.webpYou normally won't call this directly — use the URLs from the project resource's avatar field, which already point at this endpoint.
Remove Avatar
DELETE /api/projects/{id}/avatar
Deletes the stored image and its variants. Requires Projects: Update. Returns the updated project resource with avatar set to null.
bash
curl -X DELETE https://{tenant}.kendo.dev/api/projects/3/avatar \
-H "Authorization: Bearer your-token"Pin / Unpin Project
POST /api/projects/{id}/pin
Toggles the project as "pinned" for the authenticated user, personalizing their own sidebar — it does not affect any other user's view of the project. Requires the same access as viewing the project. Calling this endpoint again on an already-pinned project unpins it.
The response is your own profile, with pinned_project_ids reflecting the new state — not the project resource.
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/3/pin \
-H "Authorization: Bearer your-token"json
{
"id": 1,
"first_name": "Ada",
"last_name": "Lovelace",
"pinned_project_ids": [3]
}See Also
- Issues API — Manage issues within a project
- Sprints API — Sprint management
- Epics API — Epic management
- Projects guide — Working with projects in the UI