DocumentationBrowse
Case files
Upload your own documents once, then let a request pull the relevant passages. Text only for now: send extracted text, not a PDF. The concepts behind the screening report are in Case files and injection.
POST /files
| Field | Type | Limit |
|---|---|---|
name | string | 1 to 200 characters. Shown back to you in the injection report, so use the exhibit name a human would recognise. |
text | string | 1 to 2,000,000 characters of extracted text. |
{
"id": "cd044ac7-85ec-4430-b37b-1bf6a966cf5f",
"name": "smith-v-jones-tolling.txt",
"chunks": 1,
"injection": {
"verdict": "clean", // clean | suspicious | hostile, scanned over the WHOLE document
"rules": [],
"hidden_chars": 0, // invisible characters stripped before storage
"excerpt": null // the first flagged span, when there is one
},
"note": "Text only for now (send extracted text). Retrieved for your requests when docketrouter.case_file is true. Never shared across owners."
}The upload scan covers the entire document, which makes it the more complete of the two screening reports. Store injection.verdict and injection.rules against the exhibit in your own system when you upload it.
A schema failure on this endpoint returns {"error":{"formErrors":[],"fieldErrors":{…}}} with HTTP 400, not the {"error":{"message","type"}} envelope. Branch on the status code.
GET /files
{
"data": [
{ "id": "3fff3496-…", "name": "opposing-counsel-exhibit-14.txt",
"chars": 255, "chunks": 1,
"created_at": "2026-08-27T18:24:34.235Z",
"retention_days": null }
]
}| Field | Meaning |
|---|---|
chars | Length of the text you uploaded. |
chunks | How many retrievable pieces it was split into, at roughly 1,200 characters each. |
retention_days | Always null through the API today. There is no automatic expiry: a file lives until you delete it. |
The list endpoint never returns document text. To see what a document contains, read your own copy.
DELETE /files/:id
{ "ok": true }Deleting removes the file row and every chunk. The call is scoped to your owner id, so deleting an id you do not own is a no-op that still returns { "ok": true }. Confirm with GET /files if you need proof.
The full workflow
# 1. upload extracted text
curl https://docketrouter.ai/api/v1/files \
-H "Authorization: Bearer dr-…" -H "content-type: application/json" \
-d '{ "name": "smith-v-jones-tolling.txt",
"text": "MEMORANDUM. The parties executed a tolling agreement on March 3, 2024 …" }'
# 2. ask a question that pulls from it
curl https://docketrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer dr-…" -H "content-type: application/json" \
-d '{ "model": "deepseek/deepseek-v4-flash", "max_tokens": 1200,
"messages": [{ "role": "user", "content": "What does the tolling agreement in my case file say?" }],
"docketrouter": { "case_file": true } }' \
| jq '{blocks: .docketrouter.injection.blocks, verdict: .docketrouter.injection.verdict}'
# 3. list, then clean up
curl https://docketrouter.ai/api/v1/files -H "Authorization: Bearer dr-…"
curl -X DELETE https://docketrouter.ai/api/v1/files/cd044ac7-… -H "Authorization: Bearer dr-…"Limits and scoping
| Limit | Value | On breach |
|---|---|---|
name | 200 characters | 400 |
text | 2,000,000 characters per upload | 400 |
| Chunk size | roughly 1,200 characters, hard split above 1,800 | n/a |
| Chunks retrieved per request | 6 | silently capped |
| Characters fenced per chunk | 1,500 | silently clipped |
| Files per account | no documented limit today | n/a |
| Retention | none; files persist until deleted | n/a |
Owner scoping
Every case-file row carries an owner id and every query filters on it. The owner is your account id when the key belongs to an account, and otherwise the key itself. That distinction matters in one practical way: a key minted outside an account owns its own files, so rotating or revoking that key changes what a request can see. Keys that belong to an account share the account's files.
Something here wrong or missing? Mail hello@docketrouter.ai with the request_id and we will fix the docs or the API, whichever is broken.