Claude Fable 5.2 API: Connect, Check Output, and Estimate Cost

Use the exact Fable 5.2 model ID, build a native request, preserve tool history, and calculate token costs without confusing catalog support with tested features.

An orange plug contact aligns with its matching socket in a flat editorial illustration.

For a new Fable 5.2 integration, use an exact model ID, make one small request, and check the returned text and stop reason before adding tools or moving existing conversations. On Ofox, the catalog ID is anthropic/claude-fable-5.2; on the Claude API it is claude-fable-5-2. Those identifiers belong in different provider configurations.

This guide separates the published model contract, Ofox’s current catalog, and application-side checks. Documentation, catalog, and a small native-protocol API test were checked on November 10, 2026. The cURL body below was tested; SDK snippets illustrate the equivalent integration pattern and were not separately exercised against the service. Ofox publishes this blog and provides the gateway discussed here.

Choose the endpoint and exact ID together

RouteModel identifierRequest endpoint
Claude APIclaude-fable-5-2https://api.anthropic.com/v1/messages
Ofox, Anthropic protocolanthropic/claude-fable-5.2https://api.ofox.ai/anthropic/v1/messages
Ofox, OpenAI-compatible Chat Completionsanthropic/claude-fable-5.2https://api.ofox.ai/v1/chat/completions

The official overview lists a 1M-token context window and a maximum 128K-token output. These are ceilings, not a sensible default request size. Start with a short, non-sensitive input and a bounded output allowance.

The Ofox model page and public catalog list Anthropic and OpenAI protocols, with aws_bedrock as the currently listed provider type for 5.2. A protocol label does not prove that every Anthropic beta feature is passed through by every route. Test the particular feature before making it a dependency.

One easy version mistake: in our dated catalog snapshot, claude-fable-latest remains an alias on the 5.1 entry. Use the exact 5.2 ID for rollout tests, and record the response model and request ID. Do not assume an alias moved because a new version launched.

Send a small native request

Create an API key using the Ofox authentication instructions and load it into OFOX_API_KEY through your normal secret manager. Run this on a server or local development machine, not in publicly shipped browser code. The following body intentionally omits sampling, forced tool selection, and optional beta controls.

curl --fail-with-body --max-time 180 \
  https://api.ofox.ai/anthropic/v1/messages \
  -H "x-api-key: $OFOX_API_KEY" \
  -H 'anthropic-version: 2023-06-01' \
  -H 'content-type: application/json' \
  --data '{
    "model": "anthropic/claude-fable-5.2",
    "max_tokens": 4096,
    "output_config": {"effort": "low"},
    "messages": [{
      "role": "user",
      "content": "A synthetic order contains 3 units at USD 12 each. Return the total and one calculation line. Do not use tools."
    }]
  }' > response.json

The expected arithmetic is USD 36. Our actual response returned that amount and the calculation, with HTTP 200, stop_reason: "end_turn", 46 input tokens, and 32 output tokens. This single synthetic request verifies that narrow case, not every production workflow. Inspect your own response.json before proceeding. An HTTP success alone does not establish that the model returned the answer, followed the task, or finished within the output limit.

Use this small inspection script to avoid assuming the first content block contains text:

import json
from pathlib import Path

response = json.loads(Path("response.json").read_text())
if "error" in response:
    raise RuntimeError(response["error"])
text = "\n".join(
    block.get("text", "") for block in response.get("content", [])
    if block.get("type") == "text"
)
print("model:", response.get("model"))
print("stop_reason:", response.get("stop_reason"))
print("usage:", response.get("usage"))
print(text)
if response.get("stop_reason") != "end_turn" or not text.strip():
    raise SystemExit("Not a completed text answer; inspect before continuing.")

For this no-tool probe, require a completed text answer and manually check the calculation. For a production task, replace that manual check with an independent validator appropriate to the output. A substring test for 36 would be inadequate: “the total is not 36” also contains it.

The native Messages documentation gives the endpoint and authentication format. If your application instead uses Chat Completions, use its messages, response, and tool-result shapes throughout. Do not paste native tool_result blocks into an OpenAI-format conversation and assume the adapter will reconstruct the original state.

Give thinking and the answer enough room

Fable 5.2 uses always-on adaptive thinking. output_config.effort controls effort; it does not change the price of an individual token. The small probe uses low to constrain a trivial task. That setting is not a recommendation for a difficult repository repair or multi-stage analysis.

For substantive work, start from the model’s documented high default and compare it with lower effort on your acceptance cases. Anthropic’s effort guidance recommends reserving higher settings for tasks where the added effort helps. Measure total tokens and completion, not just how polished the answer sounds.

max_tokens covers thinking plus response output. A small cap can therefore produce a thinking block followed by stop_reason: "max_tokens", with no visible answer. That is different from a 400 request error. Inspect the stop reason, then deliberately increase the allowance or reduce effort. Do not blindly retry the same cap many times and call the resulting spend a model price comparison.

Stream without losing the final message

When using the official Python SDK, retain the assembled message after streaming. The following is a template for a recent SDK with the documented output_config field. Record and pin the SDK version you validate in your application.

import os
import anthropic

client = anthropic.Anthropic(
    api_key=os.environ["OFOX_API_KEY"],
    base_url="https://api.ofox.ai/anthropic",
    max_retries=0,
    timeout=180.0,
)
with client.messages.stream(
    model="anthropic/claude-fable-5.2",
    max_tokens=4096,
    output_config={"effort": "low"},
    messages=[{"role": "user", "content": "Calculate 3 times 12."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    final_message = stream.get_final_message()
print(final_message.stop_reason, final_message.usage)

The text stream is for display. It is not the complete message you should save for a later tool turn. If the connection breaks before completion, mark that attempt incomplete; do not store a partial visible transcript as a valid assistant response. See the existing thinking-signature diagnostic for the fields a text-only collector can lose.

Add one read-only tool before adding side effects

A useful first tool returns a synthetic inventory record. Define lookup_stock with an input schema requiring a string SKU, set tool_choice to auto, and ask the model to check SKU DEMO-001. Validate the generated tool name and arguments against your allowlist before executing it.

For a complete executable alternative, use the read-only stock runner with its checkpoint module. That version defines read_stock for all three fixture rows and includes the initial request, tool validation, actual result message, continuation, and final handoff check. The step-by-step instructions separate local checks from explicitly paid execution.

For the native protocol, append the entire assistant content exactly as returned. Then append a user message containing the real result and the matching tool ID:

# response is the completed SDK response; tool is one validated tool_use block.
messages.append({
    "role": "assistant",
    "content": [b.model_dump(exclude_none=True) for b in response.content],
})
messages.append({"role": "user", "content": [{
    "type": "tool_result",
    "tool_use_id": tool.id,
    "content": '{"sku":"DEMO-001","available":7,"source":"synthetic fixture"}'
}]})

This fragment illustrates the continuation shape, not a complete multi-tool runner. If multiple calls are returned, handle every call ID and report each actual result. A tool failure needs an error result, not an invented successful record. The missing tool_result guide explains pairing failures; the 5.2 upgrade guide covers version-specific restrictions.

Do not equate auto with “the tool must execute.” Your application must detect a text-only answer when the task requires a lookup, and refuse to mark that task complete. Begin with a read-only fixture so that debugging retries cannot submit orders or send messages twice.

Calculate the bill using separate token categories

Standard USD rates per million tokens, checked November 10:

CategoryClaude API published rateOfox catalog list rate
Uncached input$8$8
Output$40$40
5-minute cache write$10$10
1-hour cache write$16$16
Cache read$0.20$0.20

Sources: Anthropic pricing, the Ofox model page, and our dated catalog snapshot. Ofox’s repository defines these catalog fields as USD per token; the table multiplies them by one million. Its repository code reads dynamic model data, so the Git source alone is not a current price list. The 5.2 snapshot has no separate provider_price object; that is missing supplier-price data, not a zero supplier cost or a verified discount.

For an uncached illustrative request with 20,000 input tokens and 4,000 billed output tokens:

20,000 × $8 / 1,000,000 + 4,000 × $40 / 1,000,000 = $0.32

For an illustrative request with 19,000 cache-read tokens, 1,000 uncached input tokens, and the same output:

19,000 × $0.20 / 1,000,000 + 1,000 × $8 / 1,000,000
+ 4,000 × $40 / 1,000,000 = $0.1718

The second example excludes the earlier cache-write request. Add that request when estimating a whole session. Use mutually exclusive input categories, and never add cache-write tokens to uncached input a second time. Count billed reasoning output, retries, and any separately charged tools. These are calculations, not observed invoices. Batch or fast-mode rates require their own eligibility and routing checks; they are not applied here.

Recorded API responses and validation from the synthetic November 10 test

Screenshot of our locally rendered test record, populated from actual API responses. This is not an Ofox product-interface screenshot.

Decide whether the integration is ready

Our additional native-protocol probes completed a streamed text response and a read-only tool round trip. Two deliberately incompatible-parameter probes also returned 200: one sent thinking: {"type":"disabled"}, and one forced lookup_stock while the prompt requested arithmetic without tools. The latter returned text without a tool call. Neither response proves that those controls worked. The route-specific results in the 400 article explain why application acceptance checks remain necessary.

Before moving traffic, require four outcomes: a completed text request; a complete stream; a read-only tool round trip with correct IDs; and an existing multi-turn session restored without altered history. Keep request IDs, exact model, effort, usage, stop reason, SDK version, and the acceptance result for each case.

For a 400, diagnose the body instead of retrying unchanged. For overload, use bounded retries and consult the Claude 529 guide. For a model switch, preserve application facts separately from opaque reasoning using the checkpoint tutorial. The 5.2 versus 5.1 and Opus 5.5 comparison supplies the cost and migration decision.

Related documentation: API authentication, native Messages, and provider routing. Confirm retention requirements with the actual service handling your data: Anthropic documents model-specific retention requirements for 5.2, and an Ofox protocol-support label is not a privacy guarantee.