The Kimi Files API provides a programmatic lifecycle for uploading a file, retrieving its extracted text, using that text in a model request and deleting the uploaded resource. The important implementation detail is that upload alone does not make a file answer accurate: your application must retrieve the extracted content, pass the relevant text to the model and validate the answer independently.
We ran one fail-closed PDF lifecycle against the Global Kimi API. Upload and content retrieval each returned HTTP 200, and the extracted text contained all 10/10 frozen markers. One kimi-k3 Q&A request passed 2/5 strict answer-shape checks at a usage-derived cost of $0.007461. The delete request returned HTTP 200, but the one preregistered GET /files/{id} verification returned HTTP 500 instead of 404. We stopped there. DOCX and CSV were not run.
Independent test result, August 7, 2026: PDF upload 200; content retrieval 200; extraction 10/10; Q&A HTTP 200 and 2/5 under the frozen strict oracle; delete 200; one deletion-verification GET 500. No retry or corrective run was made. A separate read-only
GET /fileslater showed zero listed files and zero listed bytes at2026-08-07T17:34:02.286Z. That later inventory does not turn the failed single-resource verification into a pass.
Kimi AI Guide is independent and is not affiliated with Moonshot AI or Kimi.
Result at a glance
| Stage | PDF observation | Classification |
|---|---|---|
POST /files with purpose=file-extract | HTTP 200 | Upload request passed once |
GET /files/{id}/content | HTTP 200 | Content retrieval passed once |
| Frozen extraction markers | 10/10 present | Extraction marker check passed |
POST /chat/completions | HTTP 200; kimi-k3; finish_reason: stop | Transport completed once |
| Strict Q&A oracle | 2/5 | Failed strict answer contract |
| Usage-derived Q&A cost | $0.007461 | Dated calculation, not a billing-posting claim |
DELETE /files/{id} | HTTP 200 | Delete request succeeded once |
One GET /files/{id} verification | HTTP 500; expected 404 | Verification failed; no retry |
Independent later GET /files | 0 files; 0 bytes | Point-in-time empty list, not a 404 substitute |
| DOCX fixture | NOT RUN | No acceptance, extraction, Q&A or cleanup result |
| CSV fixture | NOT RUN | No acceptance, extraction, Q&A or cleanup result |
The defensible conclusion is narrow: one synthetic PDF uploaded and extracted successfully; its strict Q&A contract failed 3 of 5 fields; deletion returned 200 but the required follow-up resource check returned 500; the later file list was empty. This is not a cross-format reliability rate.
This page is for the API, not consumer Kimi file upload
This page owns developer intent: HTTP endpoints, purpose=file-extract, extracted-content handling, model context, strict scoring, resource deletion and cleanup evidence.
For uploading a document in the Kimi web interface, dealing with long-document context or choosing a consumer workflow, use Using Kimi with Files and Long Documents. A successful browser upload and a successful API lifecycle are different products and should not be treated as interchangeable tests.
For API authentication and a first text request, start with the Kimi API guide. This page assumes that your server already holds a valid API key securely.
The documented Files API lifecycle
Kimi’s current Files upload reference documents POST /files with the upload purpose file-extract. The current per-file limit shown there was 100 MB when checked on August 7, 2026. A size ceiling is not a guarantee that a scanned page, table, chart, formula or unusual encoding will extract correctly.
Kimi’s file-based Q&A guide uses this sequence:
- upload the file for extraction;
- retain the returned file ID only as long as the application needs it;
- retrieve the extracted content;
- place the relevant extracted text in the model context;
- ask a bounded question;
- validate the output against your own rules; and
- delete the uploaded file when its lifecycle ends.
Do not assume that a chat request can use an uploaded file merely because a file_id exists. In the documented flow tested here, the application retrieves the content first and supplies that text to the model.
A minimal server-side implementation pattern
The examples below show the request boundaries; they are not a client-side browser integration. Keep the API key on your server and never place it in WordPress, public JavaScript, a downloadable fixture or a log shared with users.
1. Upload once for extraction
upload_file="synthetic-fixture.pdf"
curl --fail-with-body \
--request POST "https://api.moonshot.ai/v1/files" \
--header "Authorization: Bearer $MOONSHOT_API_KEY" \
--form "purpose=file-extract" \
--form "file=@${upload_file};type=application/pdf"
Check the HTTP status and parse the returned ID. Store that ID in a private, run-scoped cleanup record immediately. Never add a manually supplied, pre-existing or list-discovered ID to an automated deletion queue.
2. Retrieve and validate extracted text
curl --fail-with-body \
--request GET "https://api.moonshot.ai/v1/files/$FILE_ID/content" \
--header "Authorization: Bearer $MOONSHOT_API_KEY" \
--header "Accept: application/json, text/plain"
Treat extracted text as untrusted input. Before asking a model a high-stakes question, check deterministic anchors such as a document identifier, named section, total row or verification phrase. That does not prove every character is correct, but it can stop a clearly incomplete extraction from reaching the model.
3. Put the extracted content in a bounded model request
Our live runner used one kimi-k3 call with reasoning_effort: low, a 600-token maximum and response_format: {"type":"json_object"}. The relevant shape was:
const payload = {
model: "kimi-k3",
reasoning_effort: "low",
max_completion_tokens: 600,
messages: [
{
role: "system",
content:
"Use only the following extracted synthetic file content. " +
"Do not use outside facts.\n\n" + extractedText
},
{
role: "user",
content: JSON.stringify(frozenQuestionContract)
}
],
response_format: { type: "json_object" }
};
json_object ensured that the outer response could be parsed as JSON; it did not enforce the required nested types. That distinction explains our result: the response had the five expected top-level keys, but three values were prose strings where the frozen oracle required objects.
If exact structure matters, validate it locally and use the current Kimi API structured-output guidance where the selected model and schema subset support it. Valid JSON is not the same as schema compliance, and schema compliance is not the same as factual correctness.
4. Delete only the resource your run created
curl --fail-with-body \
--request DELETE "https://api.moonshot.ai/v1/files/$FILE_ID" \
--header "Authorization: Bearer $MOONSHOT_API_KEY"
Kimi’s Files deletion reference provides the deletion operation. Your application should still record the response, make a bounded verification appropriate to the documented contract and keep an explicit unresolved state if verification fails.
Do not blindly retry a deletion after an uncertain transport result. A retry may target a resource already deleted, and the second response can obscure what happened on the first attempt.
Our synthetic PDF fixture
The exact one-page PDF used in this run is available as the synthetic PDF fixture and is also included in the sanitized evidence package as fixtures/kimi-files-api-ground-truth-fixture.pdf.
| Fixture property | Frozen value |
|---|---|
| Fixture ID | KIAI-FILES-20260807-PDF-01 |
| Synthetic | Yes; no real person, account or operational record |
| Size | 3,503 bytes |
| SHA-256 | 3740399D20CD8CDB9E5DD6003D53BAF04264F6FA10233AC219286DE39BA891AE |
| Pages | 1 |
| Reporting date inside fixture | August 1, 2026 |
| Verification phrase | ORBIT-SAFFRON-4821 |
| Data | Three sites, planned/actual units, defects and synthetic owners |
The PDF was rendered at 144 DPI and inspected at original resolution before the API run. Local QA found no clipping, overlap, broken table cells, unreadable text, missing footer or page-number defect. Its locally extracted text contained 1,298 characters and all required ground-truth anchors.
The fixture’s simplicity is deliberate. It lets us separate an API or model error from a changing source, OCR ambiguity or an unknown expected answer. It does not represent a scanned report, multi-column paper, image-only PDF or long document.
Frozen test methodology
| Setting | Frozen value |
|---|---|
| Run ID | kimi-api-reliability-lab-20260807-v1-files |
| Date | August 7, 2026 |
| API region | Global, https://api.moonshot.ai/v1 |
| Planned order | PDF, DOCX, CSV |
| Upload purpose | file-extract |
| Q&A model | kimi-k3 |
| Reasoning effort | low |
| PDF maximum completion | 600 tokens |
| Q&A calls per fixture | 1 |
| Upload/content/delete/verify attempts | 1 each |
| Automatic or corrective retries | 0 |
| Execution | Sequential, fail closed |
| PDF extraction oracle | 10 exact markers |
| PDF answer oracle | 5 precomputed questions with exact types and values |
For each fixture, the planned runner verified local hashes, uploaded once, retrieved content once, checked extraction markers, made one bounded Q&A request, scored the unedited response, deleted only the ID created by that run and made one resource-verification GET.
The required cleanup-verification status was HTTP 404. Because the PDF verification returned HTTP 500, the runner stopped before opening the DOCX or CSV stages. We did not relax the condition, retry the request or record the remaining formats as failures.
Extraction result: 10/10 markers were present
The content endpoint returned HTTP 200. The extracted text contained every preregistered marker:
| Marker class | Required values | Result |
|---|---|---|
| Document identity | KIAI-FILES-20260807-PDF-01, ORBIT-SAFFRON-4821 | 2/2 |
| Site names | Cairo, Alexandria, Aswan | 3/3 |
| Totals | 295 planned, 287 actual | 2/2 |
| Synthetic owners | Mira Chen, Omar El-Sayed, Lina Park | 3/3 |
| Total | 10 exact markers | 10/10 |
This passed a marker-presence check. It does not prove byte-for-byte extraction, correct reading order, complete formatting, or performance on other PDFs.
Strict Q&A result: 2/5
The chat request returned HTTP 200 with model kimi-k3 and finish_reason: stop. The response parsed as a JSON object and included all five expected top-level keys. The strict nested answer checks produced this result:
| Question | Required result | Observed result | Strict result |
|---|---|---|---|
| Document ID and verification phrase | Object with two named fields | String: KIAI-FILES-20260807-PDF-01; ORBIT-SAFFRON-4821 | Fail |
| Total actual units | Number 287 | Number 287 | Pass |
| Site above plan and amount | Object: Alexandria, 6 | String: Alexandria, by 6 units | Fail |
| Sites meeting review rule | Array ["Cairo"] | Array ["Cairo"] | Pass |
| Zero-defect owner and count | Object: Lina Park, 0 | String: Lina Park, 0 defects | Fail |
The three failed strings contain the expected human-readable facts, but they violate the requested JSON types and field structure. We did not convert them into passes after seeing the response. For an application that reads answer.q3.site, a correct-looking sentence is still a contract failure.
This single result does not show that K3 usually scores 40% on file questions. It shows that one json_object response preserved the requested top-level keys but failed three nested shape requirements. A larger, preregistered sample would be needed for a rate.
Usage and cost
The one Q&A request reported:
| Usage field | Tokens |
|---|---|
| Prompt | 707 |
| Cached prompt | 0 |
| Uncached prompt | 707 |
| Completion | 356 |
Using the pricing snapshot frozen for the run—$3.00 per million uncached K3 input tokens, $0.30 per million cached input tokens and $15.00 per million output tokens—the usage-derived calculation is:
707 × $3.00 / 1,000,000 = $0.002121
0 × $0.30 / 1,000,000 = $0.000000
356 × $15.00 / 1,000,000 = $0.005340
Total = $0.007461
This is the calculated model-inference cost for the retained Q&A usage. It is not a claim about a separate file-processing fee, an immediate console deduction or future pricing. Check the current Kimi API pricing and limits before setting a production budget.
Delete returned 200; the required verification returned 500
The runner recorded the uploaded PDF’s provider-generated ID in a private cleanup ledger and used only that run-owned ID for cleanup. The ID is excluded from the public package.
The single delete request returned HTTP 200. The runner then made its one preregistered GET /files/{id} check. Expected: 404. Observed: 500. The runner recorded deletion verification as failed and stopped.
We do not claim that the GET returned 404. We do not claim that HTTP 500 means the file still existed. The retained result does not expose a response body that would justify a more specific explanation.
The later list check was empty, but answers a different question
An independent read-only GET /files check returned:
{
"observed_at_utc": "2026-08-07T17:34:02.286Z",
"listed_file_count": 0,
"listed_file_bytes": 0
}
This establishes that the list endpoint exposed no files at that timestamp. It supports the operational observation that no test file remained visible in the account inventory. It does not prove:
- that the single-resource endpoint would return 404 on another request;
- why the recorded request returned 500;
- immediate or permanent backend erasure;
- provider retention behavior; or
- a general cleanup success rate.
Both facts belong in the record: the required resource verification failed, and the later list view was empty.
Why DOCX and CSV are NOT RUN
The frozen protocol was sequential and fail closed. It did not authorize continuing to the next upload after unresolved cleanup verification.
| Format | Upload | Extraction | Q&A | Delete/verify | Final status |
|---|---|---|---|---|---|
| 200 | 10/10 markers | 2/5 strict | Delete 200; verify GET 500 | Partial lifecycle completed; verification failed | |
| DOCX | Not attempted | Not attempted | Not attempted | Not attempted | NOT RUN |
| CSV | Not attempted | Not attempted | Not attempted | Not attempted | NOT RUN |
NOT RUN is not a zero score and not evidence of incompatibility. We make no claim about DOCX or CSV upload acceptance, extraction quality, model answers, cost or deletion behavior from this run.
What this test supports—and what it does not
Supported by the retained evidence:
- one 3,503-byte synthetic PDF upload returned HTTP 200;
- its content endpoint returned HTTP 200;
- all 10 frozen extraction markers were present;
- one K3 Q&A call returned valid top-level JSON and passed 2/5 strict nested checks;
- the recorded Q&A usage produced a $0.007461 dated cost calculation;
- one delete request returned HTTP 200;
- one resource-verification GET returned HTTP 500 rather than 404;
- no retry or correction was made;
- the protocol stopped before DOCX and CSV; and
- a later independent list check exposed zero files and zero bytes.
Not supported:
- a general Files API success, accuracy or deletion rate;
- byte-perfect extraction or OCR performance;
- DOCX or CSV compatibility;
- a claim that all five answers passed because their prose looked correct;
- a claim that deletion was verified with HTTP 404;
- an explanation for the HTTP 500;
- proof of backend erasure or a retention-policy conclusion;
- file-processing pricing beyond the retained model usage; or
- behavior in another account, region, model or date.
Production safeguards
- Upload from a trusted server; never expose the API key in public JavaScript.
- Restrict accepted file type, byte size and filename before sending data.
- Use synthetic or minimized data for the first integration test.
- Record the local source hash before upload and keep the provider ID private.
- Retrieve extracted text and validate deterministic anchors before Q&A.
- Treat file text as untrusted input that may contain prompt injection.
- Bound model, context, output tokens, time, spend and attempt count.
- Validate parse, schema and facts separately; do not accept fluent prose when an object is required.
- Delete only IDs created by the current workflow and never ingest arbitrary IDs into cleanup.
- Keep
delete accepted,resource verificationandlist inventoryas separate states. - Do not retry an uncertain delete automatically.
- Redact keys, Authorization headers, provider IDs, request IDs, reasoning and account data from public evidence.
- Review the provider’s current data-use and retention terms before uploading confidential or regulated material.
For error-handling patterns, use the Kimi API Error Decoder. For model-generated custom functions, see Kimi API Tool Calling.
Frequently asked questions
Does uploading a file automatically make it available to a Kimi chat request?
The documented flow used here retrieves the extracted content and supplies that text in the model context. An upload ID alone is not evidence that the model read the file.
Did the PDF extraction pass?
It passed the frozen 10-marker presence check. That is narrower than byte-perfect extraction, layout preservation or a long-document benchmark.
Why is the Q&A score 2/5 if all three failed strings show the right facts?
Because the preregistered contract required objects with named fields. Three answers returned strings instead. Applications depend on types and keys, so we preserved those failures rather than rescoring them after the run.
Was the uploaded PDF deleted?
The delete request returned HTTP 200, and a later independent list request exposed zero files and zero bytes. However, the required one-resource verification returned HTTP 500 rather than 404. We therefore report the deletion request as accepted but the preregistered 404 verification as failed.
Did you test DOCX and CSV?
No. The fail-closed protocol stopped after the PDF verification error. Both formats are NOT RUN.
Should an application retry HTTP 500 after deleting a file?
Not automatically. The delete may already have taken effect. Preserve the first result, check the current official contract and use a bounded, explicitly authorized reconciliation process that cannot delete an unrelated resource.
Is the $0.007461 figure a provider invoice?
No. It is calculated from the API-reported token usage and the dated pricing snapshot frozen for the run. It does not establish a separate file-processing charge or the timing of an account deduction.
Downloadable evidence
Download the Kimi Files API Evidence Bundle. It is 11,814 bytes with SHA-256 DE87D50D9CAB61BF07D263C02186FCC32CFD71DC3EB918D033CCC46874ED5CA1. It contains the exact PDF, ground truth, frozen oracle, fixture QA, sanitized result, methodology, manifest and SHA-256 checksums. A fresh public download matched the local byte count and hash exactly.
The package excludes the API key, Authorization header, provider-generated file ID, private cleanup ledger, account/project identifiers, balance data, provider request IDs and returned reasoning content.
Official sources and evidence boundary
- Kimi Files upload API — vendor-documented upload route,
file-extractpurpose and current file-size limit. - Kimi file-based Q&A guide — vendor-documented content-retrieval and model-context flow.
- Kimi Files deletion API — vendor-documented deletion operation.
- Kimi API models — current model identifiers and availability.
- Kimi API pricing and limits — time-sensitive model pricing, limits and account requirements.
The endpoint descriptions above come from current official documentation checked on August 7, 2026. Every HTTP status, score, token count, cost calculation, timestamp and limitation in the result sections comes from this independent single-pass run or its explicitly identified later read-only list observation.
