← Blog

Claude API JSON Mode Output Format Guide

2026-10-07 · 5 min read · SubToAPI Team

If you're searching for a "JSON mode" toggle in the Claude API, the short answer is: it doesn't exist — not in the way OpenAI's response_format: json_object works. Claude has no dedicated API parameter that forces strict JSON output. What it does have is a set of reliable techniques — tool use, prompt prefilling, and strict schema instructions — that get you valid, parseable JSON on nearly every request.

This matters because a lot of production systems need Claude's output to feed directly into a database, a frontend component, or another API call, with zero tolerance for stray prose like "Here's the JSON you requested:". Below are the three approaches that actually work, ranked by reliability.

Why there's no native JSON mode

Anthropic's Messages API accepts a system prompt, a list of messages, and optional tools. There's no response_format field. Claude is a conversational model by default, so without guidance it will happily wrap JSON in markdown code fences or add explanatory text before and after the object. For automated pipelines, that's a parsing nightmare — one extra backtick and your JSON.parse() throws.

The good news: Claude's tool-calling capability was effectively built to solve this exact problem, and it's the most robust option available.

Method 1: Tool use (most reliable)

Define a tool whose input schema is the JSON shape you want. Force Claude to call it with tool_choice, and Claude returns a tool_use block containing structured input that already matches your schema — no parsing games needed.

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-20250514",
    "max_tokens": 500,
    "tools": [{
      "name": "extract_invoice",
      "description": "Extract structured invoice data",
      "input_schema": {
        "type": "object",
        "properties": {
          "vendor": {"type": "string"},
          "total": {"type": "number"},
          "due_date": {"type": "string"}
        },
        "required": ["vendor", "total", "due_date"]
      }
    }],
    "tool_choice": {"type": "tool", "name": "extract_invoice"},
    "messages": [{"role": "user", "content": "Invoice from Acme Corp, total $1,240.50, due March 15."}]
  }'

The response's content array contains a tool_use object with input already shaped as JSON matching your schema. This is schema-enforced, type-checked, and the closest thing to a true "JSON mode" Claude offers. It's the method I'd default to for anything going into a database or a typed frontend.

If you're calling Claude through SubToAPI, this works identically — same request shape, same tool-calling behavior, documented at /docs/tools.

Method 2: Assistant message prefilling

If you don't want the overhead of tool schemas, you can prefill the start of Claude's response so it never gets the chance to add preamble text. By seeding the assistant turn with {, Claude continues from there instead of starting fresh.

{
  "model": "claude-sonnet-4-20250514",
  "max_tokens": 300,
  "messages": [
    {"role": "user", "content": "Return a JSON object with keys 'name' and 'age' for: John, 34 years old."},
    {"role": "assistant", "content": "{"}
  ]
}

Claude will complete the object starting right after the brace. You just need to re-prepend the { yourself when you parse the response, since the model's continuation won't repeat it. This is lightweight and works well for simple, flat objects, but it's less robust than tool use for nested or strictly-typed schemas — Claude can still occasionally drift from the exact field names or types you wanted.

Method 3: Strict prompt instructions

The simplest (and least reliable) option is to just tell Claude exactly what you want, including an explicit instruction to output nothing else:

Respond with ONLY a valid JSON object, no markdown formatting, no code fences, 
no explanation before or after. The object must have exactly these keys: 
"status" (string), "confidence" (number between 0 and 1), "reasons" (array of strings).

This works most of the time with current Claude models, especially Sonnet and Opus, but "most of the time" isn't good enough for automated pipelines that can't tolerate a parse failure. Always pair this with defensive parsing (strip code fences, trim whitespace) and a retry-on-failure path. For low-stakes use cases — a one-off script, a prototype — this is fine. For anything running unattended in production, prefer tool use.

Defensive parsing, regardless of method

Even with tool use, it's worth wrapping your parsing in a try/catch, because upstream issues (truncated responses from hitting max_tokens, for example) can still produce incomplete JSON:

function parseClaudeJSON(text) {
  const cleaned = text.replace(/```json\n?|```\n?/g, "").trim();
  try {
    return JSON.parse(cleaned);
  } catch (err) {
    throw new Error(`Failed to parse Claude output as JSON: ${err.message}`);
  }
}

If you're hitting Claude through SubToAPI, the request and response shapes match the native Anthropic API, so this same parsing logic applies without modification — see /docs/messages for the full response structure and /docs/quickstart to get an API key set up in minutes.

Streaming and JSON

If you're streaming responses (via /docs/streaming) and need JSON at the end, don't try to parse partial chunks as valid JSON — they won't be. Accumulate the full text across content_block_delta events, then parse once the stream completes. Tool-use streaming emits input_json_delta events specifically for this, letting you reconstruct the JSON argument string incrementally without false parse attempts on incomplete fragments.

Practical recommendation

questions

Does the Claude API have a response_format: json parameter like OpenAI? No. Claude has no equivalent parameter. The closest analog is forcing a tool call with a JSON schema via tool_choice, which returns structured input matching your schema.

Why does Claude sometimes wrap JSON in markdown code fences? By default Claude formats output for human readability, which includes code fences for structured data. Explicit instructions, prefilling, or tool use all prevent this behavior.

Is tool use slower or more expensive than plain text prompting for JSON output? Tool use adds minimal latency and token overhead from the schema definition, but it eliminates parsing failures and retries, which usually makes it cheaper and faster overall in production.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →