Docs/API
Files
How do I upload a file once and send it to any model?
Checked against the code on
POST https://heyaskr.ai/v1/files
GET https://heyaskr.ai/v1/files
GET https://heyaskr.ai/v1/files/{id}
GET https://heyaskr.ai/v1/files/{id}/content
DELETE https://heyaskr.ai/v1/files/{id}Upload a file once, then name it by file_id in any message. The shape is OpenAI's files API, so client.files.create in the SDKs works as it is. Uploading is free and keeping a file costs nothing; a file costs input tokens on each call that carries it, at the model's rate. The same store sits behind the paperclip in the workspace, with the same limits and the same rules.
Upload, then ask
curl https://heyaskr.ai/v1/files \
-H "Authorization: Bearer $ASKR_KEY" \
-F "file=@report.pdf" \
-F "purpose=user_data"
curl https://heyaskr.ai/v1/chat/completions \
-H "Authorization: Bearer $ASKR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-5",
"messages": [{"role": "user", "content": [
{"type": "text", "text": "Summarise this in five bullets."},
{"type": "file", "file": {"file_id": "3f2a9c1e-7b4d-4e0a-9c1f-2d8e6a5b4c3d"}}
]}]
}'The part to use for an upload follows its kind: file for a PDF, a document or a text file, image_url for a picture, input_audio for sound, video_url for a clip, each with file_id in place of the inline data. Pictures and files in a message has every shape.
The five routes
| Method | Path | What it does |
|---|---|---|
| POST | /v1/files | Multipart with a file field. purpose is accepted and ignored: every upload here is for a model to read. An optional name field sets the filename kept. Answers with the file object. 60 uploads a minute. |
| GET | /v1/files | Your newest 100 files, as { "object": "list", "data": [...] }. |
| GET | /v1/files/{id} | One file object. |
| GET | /v1/files/{id}/content | The bytes, with the stored content type and the filename. |
| DELETE | /v1/files/{id} | { "id": ..., "object": "file", "deleted": true }. A call that names the id afterwards gets 404. |
The file object
{
"id": "3f2a9c1e-7b4d-4e0a-9c1f-2d8e6a5b4c3d",
"object": "file",
"bytes": 482113,
"created_at": 1789516800,
"filename": "report.pdf",
"purpose": "user_data",
"askr": { "kind": "pdf", "mime": "application/pdf", "meta": { "pages": 12, "chars": 30412 } }
}| Field | Meaning |
|---|---|
| askr.kind | What the bytes were found to be: image, pdf, text, document, audio or video. The name and the declared type are not trusted. |
| askr.mime | The stored type, from the bytes. |
| askr.meta | What was measured: width and height for a picture; pages for a PDF; seconds for audio and video; sheets or slides for a document; chars for anything read as words, with truncated: true when it was cut at 400,000 characters. |
What is accepted
| Kind | Formats | Per file | Per message | Per request |
|---|---|---|---|---|
| Picture | PNG, JPEG, WebP, GIF | 8 MB, 8,192 pixels a side | 6 | 20 |
| 32 MB | 3 | 6 | ||
| Text and code | Plain text, Markdown, CSV, JSON, HTML, YAML and source code in most languages | 5 MB | 5 | 10 |
| Document | Word (.docx), PowerPoint (.pptx), Excel (.xlsx) | 32 MB | 3 | 6 |
| Audio | MP3, WAV, M4A, OGG, FLAC, WebM | 25 MB, 20 minutes | 2 | 4 |
| Video | MP4, MOV, WebM | 100 MB, 10 minutes | 1 | 2 |
Per request counts every file_id on every message in messages. A kind not in the table is refused with 415, and an empty or damaged file with 400, at upload. Pictures are not resized on the API: send them at the size you want the model to see, under 8 MB.
How a file reaches the model
Every model reads words. Only some read files. A file by file_id goes to the model as the file where the model's inputs on GET /v1/models include its kind, and as its words where they do not:
- Pictures go to a model with
imagein its inputs and are refused on any other (W203). 212 chat models see pictures, on the catalogue of 24 September 2026. - PDFs of up to 100 pages go as the file to a model with
filein its inputs, 113 of them: inline under 8 MB, by a link the provider fetches above it. On every other model, and over 100 pages on every model, a PDF goes as its text. A scanned PDF with no text layer works only on a model that reads files (W611otherwise). - Text, code and documents always go as words, between lines that name the file. Word is read as its paragraphs, PowerPoint one block per slide, Excel one sheet at a time as CSV. Up to 400,000 characters a file, about 100,000 tokens; a longer file is cut there and the model is told.
- Audio goes as sound to a model with
audioin its inputs, 32 of them, when it is an MP3 or a WAV under 8 MB. Anything else, and any audio for a model that cannot hear, goes as a transcript, made once by a speech-to-text model and kept beside the file. If none can be made,W608. - Video goes as the clip to a model with
videoin its inputs, 66 of them: inline under 8 MB, by a link above it. There is no words version of a video; on any other model it is refused (W609).
What it costs
A file on a call is input tokens at the model's input rate. The hold reserves the top of what providers bill per unit and settles to the gateway's real figure, in askr.credits_charged as always. Holds and settlement.
| Sent as | Reserved |
|---|---|
| A picture | 1,600 tokens |
| A PDF, as the file | 1,600 tokens a page |
| Audio, as sound | 32 tokens a second |
| Video | 100 tokens a second |
| Words: a text file, a document, a PDF's text, a transcript | The text's own token count |
Only the three newest user messages that name uploads carry them in full. On an older message the file is replaced by a one-line note saying it was attached there, so a client that resends the whole conversation, as OpenAI-shaped clients do, does not pay for a PDF on every call. Files count toward the model's window with everything else; a request that does not fit returns 413 with code context_length_exceeded before anything runs.
How long a file is kept
- Used in a call
- Kept on your account until you delete it. The workspace's Files page shows the same list.
- Never used
- Swept 7 days after upload.
- The words read from it
- Extracted text and any transcript are kept beside the file, so they are made once.
- Where it goes
- Where your words go: to the model's provider, through askr's gateway, for that call. A file over 8 MB sent as the file is fetched by the provider from a link that expires after an hour.
Errors
None of these charge anything. Refusals that share a message with the workspace carry its code in code, so Error codes reads for both.
| Status | Where | Message | Why |
|---|---|---|---|
| 400 | Upload | Send multipart/form-data with a file field. | The body was not multipart. |
| 415 | Upload | That file type is not accepted. Pictures (PNG, JPEG, WebP, GIF), PDFs, text and code files, Word, PowerPoint and Excel documents, audio (MP3, WAV, M4A, OGG) and video (MP4, MOV, WebM) are. | code is W604. Judged from the bytes. |
| 413 | Upload | That file is too large. The limit is 32 MB for a PDF. | code is W605. The message names the limit for that kind. |
| 400 | Upload | That file could not be read. It may be empty or damaged. | code is W610. |
| 404 | Files, chat | No file with id 'x'. | Deleted, swept, or on another account. |
| 413 | Chat | At most 6 pdf files per request. | More than the per-request count for that kind. |
| 400 | Chat | The model 'x' does not accept file input. Upload the file with POST /v1/files and send its file_id instead; askr then sends the model its text where it can. | An inline part on a model that takes no such input. Also image, audio and video. |
| 400 | Chat | That model cannot watch video. Pick one that does, or remove the video. | A per-model refusal of an upload: W609 here; also W203, W605, W606, W607, W608, W611. |
| 413 | Chat | This request, with its files, is about 180,000 tokens; the model 'x' takes 128,000. | code is context_length_exceeded. Pick a bigger window, or send less. |