| Method | Path | Description |
|---|---|---|
| GET | /api/projects/{projectId}/chat-sessions/{sessionId}/artifacts | Use sessions files list. List the session's files of the four kinds an agent writes. |
| POST | /api/projects/{projectId}/chat-sessions/{sessionId}/artifacts | Use sessions files attach. Point a Backlog session at a file of the project's Files, or at each file directly in a folder. Answers with one ref per file. |
| GET | /api/projects/{projectId}/chat-sessions/{sessionId}/artifacts/{artifactId} | Use sessions files get. Read one file of the session by its id or its name: a deleted one, or one of another kind, is not found. |
| GET | /api/projects/{projectId}/chat-sessions/{sessionId}/files | List the session's files: what its agent wrote, most recently changed first, a deleted one as a row that says who deleted it, then the files its ticket points at. Rows only: a body or a file url comes from reading one. |
| POST | /api/projects/{projectId}/chat-sessions/{sessionId}/files | Point a Backlog session at a file of the project's Files, or at each file directly in a folder, without copying it: its agent reads the current version when it starts. Markdown, HTML, images and videos only. The batch is refused whole on another type, on a file this session's own agent wrote, and on a name that clashes with another of the session's attached files. |
| GET | /api/projects/{projectId}/chat-sessions/{sessionId}/files/{fileId} | Read one file of the session, by its id or its name, such as testing-checklist, qa-report.html or review: a Markdown or HTML file carries its body, any other a presigned url, its media type and its size. A deleted one says who deleted it and holds no content. |
| POST | /api/prototypes/render | Render a prototype from its prototype.json, content.css and content.js, attached as three files, and save it to a Chat Session's files (projectId and sessionId) or a workspace's Files (workspaceId). A failed check answers 422 with the issues in details and saves nothing. A session token saves only to its own session, Sensei only to Files. |
Kinds
kind | In the app | Where the content is |
|---|---|---|
markdown | Document | Markdown text in body. |
html | Mockup | A self-contained HTML page in body. |
image | Image | A file behind url, with its mediaType and byteSize. |
video | Video | A file behind url, with its mediaType and byteSize. |
file | File | A file behind url. A member replaced the agent's file with one of another type, such as a PDF. |
The field a kind does not use comes back null.
List a session's files
GET .../chat-sessions/{sessionId}/files lists what the session's agent wrote, most recently changed first, then the files its ticket points at. It holds no content.
curl -s "https://app.kosuke.ai/api/projects/$PROJECT_ID/chat-sessions/$SESSION_ID/files" \
-H "Authorization: Bearer $KOSUKE_API_KEY"
{
"data": {
"files": [
{
"id": "e2c79a10-5b4d-4f8e-a3c6-91d0b7f2e845",
"slug": "checkout-investigation",
"title": "Why checkout fails on Safari",
"kind": "markdown",
"version": 2,
"name": "checkout-investigation.md",
"path": "Sessions/storefront/Fix checkout on Safari/checkout-investigation.md",
"mediaType": "text/markdown",
"byteSize": 4120,
"locked": false,
"qaEvidence": false,
"reference": false,
"updatedBy": { "id": "user_2x9", "name": "Sam Lee" },
"expiredAt": null,
"deleted": null,
"replaced": null,
"createdAt": "2026-09-30T08:02:13.415Z",
"updatedAt": "2026-09-30T08:47:55.902Z"
}
]
}
}
| Field | What it says |
|---|---|
slug | The name the agent writes. When the agent writes the same slug again, version goes up by one. Only the QA Report takes the version it declares. Only the current version is kept. |
title | The agent's heading for the file. A rename in Files leaves it as it is. |
name, path | The file's name and place in Files as they are now. |
locked | The QA Report, the Testing Checklist and QA's recordings. Only Sensei changes them. |
qaEvidence | Listed in the QA evidence group: locked, and not the QA Report. |
reference | A file of Files the ticket points at, which this session did not write. |
deleted | { by, at } once a member deleted it. The row stays and holds no content. |
replaced | { by, at } once a member replaced it. The version the agent wrote is not kept. |
expiredAt | When retention deleted a recording's bytes, else null. |
The CLI command is kosuke sessions files list <projectId> <sessionId>.
Read one file
GET .../chat-sessions/{sessionId}/files/{fileId} returns the file with its content, by its id, its slug or its name with the extension. A Document or a Mockup carries its text in body, with url null. An Image or a Video carries a download URL in url, with body null:
{
"data": {
"id": "7d3f0b62-c18e-4a95-b2d7-4e6a8c1f09b3",
"slug": "settings-dark-mode",
"title": "Settings page in dark mode",
"kind": "image",
"version": 1,
"name": "settings-dark-mode.png",
"mediaType": "image/png",
"byteSize": 184233,
"body": null,
"url": "https://…",
"expiredAt": null,
"deleted": null,
"replaced": null
}
}
The download URL works for 24 hours. Read the file again for a fresh one. Request a file through its own session, because any other session answers 404. The CLI command is kosuke sessions files get <projectId> <sessionId> <fileId>.
A deleted file still answers 200, with deleted set and no content. An expired recording also answers 200, with url: null and expiredAt set.
GET .../chat-sessions/{sessionId}/files/{fileId}/download downloads the source or media bytes. An expired recording answers 410 (GONE) with Video expired on <date>: videos are kept 30 days.; a missing or deleted file answers 404. Cron Run and shared-link downloads answer the same way.
Point a ticket at a file
POST .../chat-sessions/{sessionId}/files with { "file": "prototypes/board/a-columns.html" } points a Backlog session at a file of the project's Files, or at each file directly in a folder. Nothing is copied: the agent reads the current version when the session starts. A personal space reads your Personal Files. The CLI command is kosuke sessions files attach <projectId> <sessionId> --file <path>.
The batch is refused whole on an unsupported type, on a file this session's own agent wrote, and on a name that clashes with another attached file. See Put a file on a ticket.
Who can read them
Any member of the workspace can read the files of any session in it. A share link also opens the files the session's agent wrote to people outside the workspace, as Previews describes.
The agent writes files during a turn. To get one, ask for it in a message, such as "Write your findings up as a document." To change one in Files, use kosuke files. A locked file or a folder Sensei keeps answers 403.
Older routes
The .../artifacts routes stay served for installed clients, and are deprecated. They keep their older response shape, under artifacts. A list holds only live files and references of the four kinds. A read answers 404 for a deleted file or one of another kind. POST records references and answers with them as refs.
Errors
| Status | Code | When |
|---|---|---|
| 404 | NOT_FOUND | The project, session or file does not exist, the file belongs to another session, or its download object is missing. |
| 410 | GONE | The downloaded recording has expired. A read of the file still answers 200. |
Responses and errors has the full table.