Kimi API structured output can constrain a response with JSON Schema, but HTTP 200 does not by itself prove that an application received usable JSON. We ran the same five frozen schemas once on kimi-k3, kimi-k2.7-code and kimi-k2.6, then scored JSON syntax, schema compliance and factual accuracy separately.
K3 passed 5/5 and K2.7 Code passed 5/5. K2.6 passed 0/5 at the frozen output limits. Every K2.6 request returned HTTP 200, spent nearly all of its completion budget on tokens attributed to reasoning, ended with finish_reason: "length" and exposed an empty message.content.
Correct conclusion: This 15-case single pass produced 10 exact structured outputs. It does not prove that K3 or K2.7 Code will always comply, and it does not prove that K2.6 can never produce structured output with a different configuration or larger output allowance.
Results by model
| Returned model | JSON valid | Schema valid | Oracle exact | Overall exact cases | Average wall time | Usage-derived cost |
|---|---|---|---|---|---|---|
kimi-k3 | 5/5 | 5/5 | 5/5 | 5/5 | 4,240.586 ms | $0.01309200 |
kimi-k2.7-code | 5/5 | 5/5 | 5/5 | 5/5 | 2,933.189 ms | $0.00378955 |
kimi-k2.6 | 0/5 | 0/5 | 0/5 | 0/5 | 6,370.931 ms | $0.00510460 |
| Total | 10/15 | 10/15 | 10/15 | 10/15 | Not pooled | $0.02198615 |
All 15 responses returned the exact requested model ID and HTTP 200. The average times are descriptive observations across five different tasks per model, not a controlled latency benchmark.
The 15-case matrix
The five tasks exercised different schema features and used only synthetic facts. A pass required all three independent checks to succeed.
| Frozen task | Schema features | Completion cap | K3 | K2.7 Code | K2.6 |
|---|---|---|---|---|---|
| Invoice summary | String pattern, integers, arithmetic, boolean | 192 | Pass | Pass | Fail: empty / length |
| Shipment route | Nested object, enum, fixed unique array | 256 | Pass | Pass | Fail: empty / length |
| Incident triage | Enums, unique array, boolean | 224 | Pass | Pass | Fail: empty / length |
| Nullable review | Required nullable fields and fixed flag | 192 | Pass | Pass | Fail: empty / length |
| Inventory ledger | Strict object array, order, calculated totals | 320 | Pass | Pass | Fail: empty / length |
No failed case was corrected, substituted or rerun. The matrix order was model order, then task order.
What each score means
| Score | Question | Why it remains separate |
|---|---|---|
json_valid | Does JSON.parse(message.content) succeed? | Syntactically valid JSON can still violate the requested structure |
schema_valid | Does the parsed value pass the frozen schema? | A schema-valid object can contain factually wrong values |
oracle_exact | Does the parsed value deep-equal the precomputed answer? | Exact facts can be represented in an unapproved or unsafe structure |
An API-level rejection would be an execution failure, not “invalid model JSON.” In this run, K2.6 was different: the API accepted all five requests and returned HTTP 200, but there was no visible content to parse.
A passing structured-output example
The invoice task supplied only these facts: invoice INV-2048, subtotal 12,500 cents, tax 1,750 cents and unpaid status. K3 and K2.7 Code each returned the exact oracle:
{
"invoice_id": "INV-2048",
"subtotal_cents": 12500,
"tax_cents": 1750,
"total_cents": 14250,
"paid": false
}
The same logical schema was used for all three models:
{
"type": "json_schema",
"json_schema": {
"name": "invoice_summary",
"strict": true,
"schema": {
"type": "object",
"properties": {
"invoice_id": {
"type": "string",
"pattern": "^INV-[0-9]{4}$"
},
"subtotal_cents": { "type": "integer", "minimum": 0 },
"tax_cents": { "type": "integer", "minimum": 0 },
"total_cents": { "type": "integer", "minimum": 0 },
"paid": { "type": "boolean" }
},
"required": [
"invoice_id",
"subtotal_cents",
"tax_cents",
"total_cents",
"paid"
],
"additionalProperties": false
}
}
}
This follows Kimi’s current structured-output guide: set response_format.type to json_schema, provide a named schema and use strict: true. Model-specific behavior still needs live validation rather than assuming identical support from the shared request shape.
What happened in all five K2.6 cases
| Case | Prompt tokens | Completion tokens | Reasoning tokens | Visible content | Finish reason | Wall time | Cost |
|---|---|---|---|---|---|---|---|
| Invoice | 76 | 192 | 191 | 0 characters | length | 4,512.001 ms | $0.00084020 |
| Shipment route | 78 | 256 | 255 | 0 characters | length | 7,491.619 ms | $0.00109810 |
| Incident triage | 70 | 224 | 223 | 0 characters | length | 6,806.210 ms | $0.00096250 |
| Nullable review | 72 | 192 | 191 | 0 characters | length | 5,868.425 ms | $0.00083640 |
| Inventory ledger | 92 | 320 | 319 | 0 characters | length | 7,176.398 ms | $0.00136740 |
Across the five responses, the API reported 1,184 completion tokens, of which 1,179 were attributed to reasoning. We removed the returned reasoning text from public evidence and retained only its token and character counts. Because the final visible content was empty, all three scores correctly failed.
The frozen protocol did not send an unverified reasoning-control field to K2.6, and it did not increase a failed case’s completion cap after seeing the result. A future, separately preregistered test could ask whether another supported setting or allowance changes the outcome. This page does not pretend that unrun follow-up already succeeded.
Token use and cost
| Model | Prompt tokens | Completion tokens | Reasoning tokens | Cached prompt tokens | Calculated cost |
|---|---|---|---|---|---|
kimi-k3 | 1,759 | 521 | 244 | 0 | $0.01309200 |
kimi-k2.7-code | 1,269 | 646 | 429 | 0 | $0.00378955 |
kimi-k2.6 | 388 | 1,184 | 1,179 | 0 | $0.00510460 |
| Total | 3,416 | 2,351 | 1,852 | 0 | $0.02198615 |
Costs were calculated from returned usage under the frozen August 4, 2026 price snapshot. They are usage-derived estimates, not tax invoices. K3 used the frozen low reasoning setting; the other two requests omitted reasoning_effort. Prompt-token totals therefore should not be treated as a tokenization or efficiency leaderboard.
For current plan and rate context, use the Kimi API pricing guide and API cost calculator. This URL owns the structured-output behavior and evidence, not the general pricing intent.
Validate JSON and schema locally
Private browser tool
Validate JSON against a schema
Check JSON parsing and a documented schema subset locally. Results identify each issue with a JSON Pointer path.
Validation result
- Instance parse
- Schema parse
- Schema support
- Instance result
Issues
The local validator is designed to answer two bounded questions: “Is this valid JSON?” and “Does it satisfy the supplied supported schema?” It must not send the schema or output to Kimi, store pasted data or request an API key.
The bundled deterministic validator supports only the keywords used by our five fixtures:
type, including type arrays;properties,requiredandadditionalProperties: false;items,minItems,maxItemsanduniqueItems;enumandconst;pattern,minLengthandmaxLength; andminimumandmaximum.
It is not a complete JSON Schema implementation. It does not prove that a value is factually true, safe to execute or accepted by every Kimi model. In retained Draft and public QA, a supported valid object passed, a deliberately invalid object produced the two expected path-specific issues, reset cleared both inputs and results, and only the block-specific assets loaded. The public page and validator were also rechecked at 1280 and 390 CSS pixels with no page or tool overflow.
Production validation pattern
Do not treat finish_reason: "stop", HTTP 200 or SDK object construction as the application boundary. Check the content in this order:
function validateStructuredResponse(response, schema, oracle) {
const choice = response?.choices?.[0];
const content = choice?.message?.content;
if (choice?.finish_reason !== "stop") {
return { ok: false, stage: "finish_reason", value: choice?.finish_reason };
}
if (typeof content !== "string" || content.length === 0) {
return { ok: false, stage: "empty_content" };
}
let parsed;
try {
parsed = JSON.parse(content);
} catch (error) {
return { ok: false, stage: "json_parse", error: String(error) };
}
const schemaResult = validateSchema(parsed, schema);
if (!schemaResult.valid) {
return { ok: false, stage: "schema", errors: schemaResult.errors };
}
return {
ok: true,
parsed,
oracleExact: oracle === undefined ? null : deepEqual(parsed, oracle),
};
}
In production, use a maintained validator that implements the exact JSON Schema dialect and keywords your application accepts. Keep factual or business-rule checks outside the generic schema layer.
Common structured-output mistakes
| Mistake | Why it fails | Safer practice |
|---|---|---|
| Parsing before checking content | A 200 response can still contain an empty visible message | Check status, finish reason and non-empty content first |
| Calling valid JSON “schema compliant” | JSON syntax says nothing about required fields or types | Run a local schema validator |
| Calling schema-valid data “accurate” | A well-shaped value can still be wrong | Compare calculated or source-backed fields with an independent oracle |
Omitting additionalProperties: false | Unexpected fields may pass into downstream code | Reject extras where the supported schema dialect allows it |
| Silently raising limits until a pass | The published result becomes cherry-picked | Freeze limits, retain the failure and preregister a follow-up |
| Treating one model result as universal | Current per-model behavior can differ | Record exact requested and returned model IDs |
| Logging the full response | Prompts, outputs or reasoning can expose private data | Retain bounded redacted evidence and necessary usage fields only |
Download the 15-case evidence bundle
Download the Kimi API Structured Output Evidence Bundle. It contains the frozen protocol and matrix, five schemas, five precomputed oracles, 15 sanitized requests, 15 sanitized responses, 15 separate score files, the track-only spend ledger, summary, local validator, offline tests and a SHA-256 manifest.
Package SHA-256: 588EB0728BC66A0D5D1366889493500D642319B92A4505C30219455004BE92B5 Package size: 61,996 bytes Files: 67, including the manifest
The manifest independently rechecked 66 covered files with zero hash or byte-count mismatch. Both dependency-free offline evidence tests passed. The ZIP contains no backslash entry, no detected API-key pattern, no private account preflight and no returned reasoning text.
Methodology and limits
- Protocol version 1.0 and every schema, oracle, prompt and completion cap were frozen before the first response.
- Run ID:
kimi-api-reliability-lab-20260807-v1. - Official Global endpoint:
https://api.moonshot.ai/v1. - Matrix: three exact model IDs by five exact synthetic tasks.
- Every case had one attempt; automatic and corrective retries were disabled.
- K3 used
reasoning_effort: low; K2.7 Code and K2.6 omitted that field. - Temperature and sampling fields were omitted rather than guessed.
- Every object schema required all intended fields and set
additionalProperties: false. - The local validator covers only the documented subset listed above.
- The five tasks are small, clean and deterministic. They do not measure arbitrary extraction, long documents, adversarial JSON, repeated reliability or production latency.
- The K2.6 conclusion is limited to these five requests, output caps, account, endpoint and date.
- Costs use returned usage and a dated local price snapshot; prices can change.
Read How We Test Kimi AI for our evidence labels and stop rules. Report a factual or scoring issue through Sources & Corrections.
Frequently asked questions
Does Kimi API support JSON Schema structured output?
The current official guide documents response_format.type: "json_schema" with strict: true. In our run, all 15 requests were accepted with HTTP 200. K3 and K2.7 Code returned exact schema-valid JSON in all five cases each; K2.6 exposed empty final content in all five frozen cases.
Does 10/15 mean Kimi is 66.7% reliable?
No. This was one pass over five synthetic tasks on each of three different models. It is a transparent case count, not a population estimate or reliability benchmark.
Why count JSON, schema and accuracy separately if all three totals match?
They happened to match here because ten outputs were exact and five were empty. In another run, parseable JSON could violate the schema, or schema-valid JSON could contain a wrong total. The separate checks prevent those failures from being hidden.
Did K2.6 return malformed JSON?
No visible JSON was returned. Each request ended with finish_reason: "length" and an empty message.content, so parsing failed at the empty-input boundary.
Should I simply increase the K2.6 completion limit?
That is a plausible new test, not a completed result. We did not alter and rerun failed cases. If you test another allowance, record it as a new protocol version and keep the original 0/5 result intact.
Does the local validator prove the facts are correct?
No. It checks JSON syntax and a limited schema subset. Factual and business-rule accuracy requires a separate oracle or trusted source.
Official sources
- Kimi API structured output and JSON Schema
- Kimi API models and exact model IDs
- Kimi API limits and billing eligibility
For broad K3 testing, use the Kimi K3 API pilot. Model specifications remain on the K3, K2.7 Code and K2.6 profiles. For setup and authentication, start with the Kimi API guide.
