Kimi API Structured Output & JSON Schema Test

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 modelJSON validSchema validOracle exactOverall exact casesAverage wall timeUsage-derived cost
kimi-k35/55/55/55/54,240.586 ms$0.01309200
kimi-k2.7-code5/55/55/55/52,933.189 ms$0.00378955
kimi-k2.60/50/50/50/56,370.931 ms$0.00510460
Total10/1510/1510/1510/15Not 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 taskSchema featuresCompletion capK3K2.7 CodeK2.6
Invoice summaryString pattern, integers, arithmetic, boolean192PassPassFail: empty / length
Shipment routeNested object, enum, fixed unique array256PassPassFail: empty / length
Incident triageEnums, unique array, boolean224PassPassFail: empty / length
Nullable reviewRequired nullable fields and fixed flag192PassPassFail: empty / length
Inventory ledgerStrict object array, order, calculated totals320PassPassFail: empty / length

No failed case was corrected, substituted or rerun. The matrix order was model order, then task order.

What each score means

ScoreQuestionWhy it remains separate
json_validDoes JSON.parse(message.content) succeed?Syntactically valid JSON can still violate the requested structure
schema_validDoes the parsed value pass the frozen schema?A schema-valid object can contain factually wrong values
oracle_exactDoes 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

CasePrompt tokensCompletion tokensReasoning tokensVisible contentFinish reasonWall timeCost
Invoice761921910 characterslength4,512.001 ms$0.00084020
Shipment route782562550 characterslength7,491.619 ms$0.00109810
Incident triage702242230 characterslength6,806.210 ms$0.00096250
Nullable review721921910 characterslength5,868.425 ms$0.00083640
Inventory ledger923203190 characterslength7,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

ModelPrompt tokensCompletion tokensReasoning tokensCached prompt tokensCalculated cost
kimi-k31,7595212440$0.01309200
kimi-k2.7-code1,2696464290$0.00378955
kimi-k2.63881,1841,1790$0.00510460
Total3,4162,3511,8520$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.

Supported subset: types, required, properties, additionalProperties, enum, const, numeric and item bounds, pattern, nested items, local $defs references, oneOf and nullable type unions.

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, required and additionalProperties: false;
  • items, minItems, maxItems and uniqueItems;
  • enum and const;
  • pattern, minLength and maxLength; and
  • minimum and maximum.

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

MistakeWhy it failsSafer practice
Parsing before checking contentA 200 response can still contain an empty visible messageCheck status, finish reason and non-empty content first
Calling valid JSON “schema compliant”JSON syntax says nothing about required fields or typesRun a local schema validator
Calling schema-valid data “accurate”A well-shaped value can still be wrongCompare calculated or source-backed fields with an independent oracle
Omitting additionalProperties: falseUnexpected fields may pass into downstream codeReject extras where the supported schema dialect allows it
Silently raising limits until a passThe published result becomes cherry-pickedFreeze limits, retain the failure and preregister a follow-up
Treating one model result as universalCurrent per-model behavior can differRecord exact requested and returned model IDs
Logging the full responsePrompts, outputs or reasoning can expose private dataRetain 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

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.