CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Guaranteed JSON From Claude: Two Native API Patterns That Never Need a Retry Loop

Guaranteed JSON From Claude: Two Native API Patterns That Never Need a Retry Loop

Chris Harper

3 min read

Aug 6, 2026 · 20:02 UTC

AI
Tutorial
Agents
Best Practices

The Claude API offers two orthogonal structured-output patterns — output_config JSON schema mode for constrained text responses and strict:true tool definitions for schema-valid tool inputs — that together eliminate JSON parse failures from agentic pipelines.

What you'll be able to do after this:

  • Get parseable JSON from Claude every time without try/except retry loops
  • Guarantee tool call inputs match your schema exactly via grammar-constrained sampling
  • Combine both patterns to build reliable agentic pipelines where Claude calls tools AND returns structured data

The two patterns

Pattern 1 controls what Claude says (its text response). Pattern 2 controls what Claude does (its tool call parameters). Both are orthogonal — use either or both together.

Pattern 1: output_config JSON schema (constrained text responses)

Pass an output_config block with a json_schema format. The API compiles your schema into a grammar and samples tokens only from schema-valid continuations — the response is always valid JSON matching your schema.

import anthropic, json

client = anthropic.Anthropic()

schema = {
    "type": "object",
    "properties": {
        "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]},
        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
        "key_phrases": {"type": "array", "items": {"type": "string"}, "maxItems": 5}
    },
    "required": ["sentiment", "confidence", "key_phrases"],
    "additionalProperties": False
}

response = client.messages.create(
    model="claude-sonnet-4-6-20260901",
    max_tokens=512,
    output_config={
        "format": {
            "type": "json_schema",
            "json_schema": {
                "name": "sentiment_result",
                "schema": schema
            }
        }
    },
    messages=[{"role": "user", "content": "Analyze sentiment: 'The new API is incredibly fast and docs are clear.'"}]
)

result = json.loads(response.content[0].text)
# {"sentiment": "positive", "confidence": 0.95, "key_phrases": ["incredibly fast", "docs are clear"]}
# sentiment is always "positive", "negative", or "neutral" — no parse error possible

Tradeoff: complex schemas with many nested objects produce larger grammars that take longer to compile on the first call. Keep schemas focused; subsequent calls with the same schema benefit from server-side caching.

Pattern 2: strict:true tool use (guaranteed tool call parameters)

Add "strict": true as a top-level property in a tool definition. When Claude calls that tool, its input always matches your input_schema — no coercion, no extra keys, no missing required fields.

tool = {
    "name": "create_task",
    "description": "Create a task in the task management system",
    "strict": True,
    "input_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string", "maxLength": 100},
            "priority": {"type": "integer", "minimum": 1, "maximum": 5},
            "assignee_id": {"type": "string", "pattern": "^usr_[a-z0-9]+$"}
        },
        "required": ["title", "priority"],
        "additionalProperties": False
    }
}

response = client.messages.create(
    model="claude-sonnet-4-6-20260901",
    max_tokens=256,
    tools=[tool],
    messages=[{"role": "user", "content": "Create a high-priority task: 'Fix the auth bug', assigned to usr_abc123."}]
)

for block in response.content:
    if block.type == "tool_use" and block.name == "create_task":
        task_data = block.input
        # task_data["priority"] is always 1-5, title always ≤ 100 chars — guaranteed

Combining both patterns

You can set strict: true on tools AND pass output_config in the same request. Claude calls tools with guaranteed-valid parameters and returns a structured final response — the right shape for multi-step agentic workflows.

response = client.messages.create(
    model="claude-sonnet-4-6-20260901",
    max_tokens=1024,
    tools=[tool],           # strict: True
    output_config={
        "format": {
            "type": "json_schema",
            "json_schema": {"name": "summary", "schema": summary_schema}
        }
    },
    messages=[{"role": "user", "content": "Create tasks for the auth bug fix and return a summary."}]
)
# Claude calls create_task (guaranteed-valid inputs) then returns structured summary JSON

This pattern is available on Claude Sonnet 4.5+, Opus 4.5+, Haiku 4.5+, and later.

Sources: Structured outputs — Claude Platform Docs · Strict tool use — Claude Platform Docs · How to implement tool use — Claude Platform Docs