Skip to content

Attach a file to a Kai thread

POST
/api/support/threads/{id}/files/
curl --request POST \
--url http://localhost:8000/api/support/threads/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/files/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form file=@file

Multipart upload (file field, ≤5 MB, ≤20 unsent files per thread). Accepted: png / jpeg / webp images and plain-text formats (txt, csv, markdown, json). The file is stored in the media bucket and joins the thread’s context: text files feed a bounded excerpt into Kai’s prompt; images are named but not analysed (no vision model yet — Kai will ask the user to describe a screenshot when it matters). A 400 with file_too_large / file_type_unsupported / too_many_files rejects an invalid upload. Feature-flagged like every thread route (404 while disabled).

id
required
string format: uuid
Media typemultipart/form-data
object
file
required
string format: binary
Media typeapplication/json

Context chip on a thread — label + kind. The snapshot content stays server-side (it is prompt material, not display material); user file attachments additionally expose a short-lived download URL + media type so the FE can render an image thumb.

object
id
required
string format: uuid
kind
required
string
<= 32 characters
label
required
string
<= 120 characters
subject_id
string format: uuid
nullable
captured_at
string format: date-time
url
required
string
nullable
media_type
required
string
nullable
Examplegenerated
{
"kind": "example",
"label": "example",
"subject_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0",
"captured_at": "2026-04-15T12:00:00Z"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string
Examplegenerated
{
"detail": "example"
}
Media typeapplication/json
object
detail
required

429 — rate limit exceeded. Honour the Retry-After response header (seconds to wait) before retrying; it is sent on every 429.

string
Examplegenerated
{
"detail": "example"
}