Skip to main content
These examples use the Enterprise plan endpoint https://enterprise.blackbox.ai. The API is also available on standard plans at https://api.blackbox.ai, where it is currently experimental.

Structuring Tool Call IDs

When sending multi-turn conversations that include tool calls, every tool_call ID and its matching tool_call_id must only contain letters, numbers, underscores, and hyphens ([a-zA-Z0-9_-]).

What causes the error

Using IDs with dots, colons, or other special characters. This commonly happens when you construct IDs yourself or copy them from provider-internal formats:

The correct way

Always use the id from the model’s response exactly as returned. If you are generating your own IDs (for example, when replaying a conversation), follow the pattern call_<alphanumeric>:
Never construct tool call IDs manually with characters like . or :. If you need to generate your own IDs (for testing or replaying conversations), use a format like call_abc123 — only alphanumeric characters, hyphens, and underscores.

Pairing Every Tool Call with a Tool Result

When the model responds with one or more tool_calls, every tool call must have a corresponding tool message with a matching tool_call_id immediately after the assistant message.

What causes the error

Sending an assistant message that contains tool_calls without providing a tool result for each one in the next turn. This commonly happens when you only handle the first tool call and ignore the rest, or when you skip the tool result entirely and send another user message instead:

The correct way

Loop through all tool_calls and send a tool message for each one:
If a tool call fails on your side, still send back a tool message for it — set the content to a JSON error like {"error": "service unavailable"}. The model can use this to adjust its response. Never skip a tool result.

Preserving Reasoning Blocks in Multi-Turn Requests

When using reasoning models with tool calling, the model returns reasoning_details alongside its response. If you send those reasoning blocks back in a follow-up request, they must be exactly as the model returned them — including any signature fields.

What causes the error

Modifying, reordering, or stripping fields from the reasoning_details before sending them back. This commonly happens when you serialize the response to a database and a field gets dropped, or when you manually rebuild the assistant message and forget the signature:
The signature was originally a cryptographic string like "erUBMkiJvNVMxLa..." but was set to null during serialization. The provider rejects the entire request because the signature no longer matches.

The correct way

Pass the entire reasoning_details array back without touching it:
The reasoning_details array contains signature fields that are cryptographically verified by the provider. If you serialize and deserialize these blocks (for example, storing them in a database), make sure no fields are dropped or altered. The entire sequence must match the original output exactly.
If you don’t need to preserve reasoning continuity across turns, you can simply omit the reasoning_details field from the assistant message. The model will start fresh reasoning for the next turn, which avoids signature validation entirely.

Avoiding Invalid Thinking Signatures

When using models with extended thinking, the model returns thinking blocks with a signature field that cryptographically validates the thinking content. If you send these blocks back in a multi-turn conversation, the signature must be intact or the API will reject the request with:

What causes the error

The signature field gets corrupted during serialization, storage, or reconstruction of the conversation history. The most common cause is null coercion — your database, ORM, or serialization layer converts the signature string to null. Common scenarios that corrupt signatures:
ScenarioWhat happensResult
ORM/DB stores signature as nullable columnValue becomes NULL on read400 error
JSON.parse → modify → JSON.stringify drops fieldsignature key missing entirelySilently accepted (but no continuity)
Manual reconstruction with signature: nullExplicit null value400 error
Signature string truncated (e.g. column length limit)Partial signature400 error
Thinking blocks stripped entirelyNo thinking in historySilently accepted (fresh reasoning)

How to reproduce

There are three ways to trigger this error. All examples below use the Blackbox AI endpoint — get a valid response first, then corrupt the signature before sending it back. Setup (shared across all examples):
1. Null coercion — the most common cause. Your ORM, database, or serialization layer converts the signature string to null:
2. Truncation — the signature string is cut short, e.g. by a VARCHAR(255) column that can’t hold the full signature (often 500–1500 characters):
3. Character corruption — the signature is modified during encoding, URL-escaping, or manual string manipulation (e.g. replacing characters, re-encoding base64):
Omitting reasoning_details entirely (or stripping thinking blocks completely) does not cause an error — the model simply starts fresh reasoning. The error only occurs when you include a thinking block with a corrupted signature value.

The fix

Option 1 (recommended): Pass thinking blocks back exactly as received. Do not serialize individual fields — store and return the entire reasoning_details array as an opaque blob:
Option 2: Strip thinking blocks entirely. If you cannot guarantee the signature will survive your storage pipeline, omit reasoning_details from previous assistant turns. The model will start fresh reasoning each turn:
Database storage checklist:
  • Store reasoning_details as a single JSON/JSONB column — not as separate fields
  • Ensure the column has no character length limit (signatures can be 1000+ characters)
  • Do not use ORMs that auto-convert unknown fields to null
  • Test round-trip serialization: parse(stringify(reasoning_details)) should produce byte-identical output
Thinking signatures work across providers (e.g. a response from blackboxai/anthropic/claude-opus-4.6 can be sent to blackboxai/vertex_ai/claude-opus-4.6 and vice versa). You do not need to pin the provider — only the content integrity matters.

GPT-5.4 Parameter Compatibility

GPT-5.4 (and other GPT-5 reasoning models) restrict certain parameters based on the reasoning_effort setting. Sending unsupported parameters will return a 400 error like:

Which parameters are restricted

The following parameters are only supported when reasoning_effort is set to none:
ParameterWith reasoning_effort=noneWith reasoning_effort=low/medium/high
temperature (values other than 1)SupportedRejected
top_pSupportedRejected
logprobsSupportedRejected
temperature=1 is always allowed regardless of reasoning effort. For full details, see OpenAI’s GPT-5.4 parameter documentation.

What causes the error

Sending temperature, top_p, or logprobs with a reasoning effort other than none:

The fix

Option 1: Set reasoning_effort to none when you need sampling parameters. This disables reasoning and allows full control over temperature, top_p, and logprobs:
Option 2: Remove sampling parameters when reasoning is enabled. If you want reasoning, don’t send temperature, top_p, or logprobs:
This restriction applies to all GPT-5 reasoning models including gpt-5.4, gpt-5.3-codex, gpt-5.2-codex, and gpt-5. The only exception is temperature=1, which is always accepted.

Avoiding Thinking with Forced Tool Choice

When using extended thinking (reasoning), you cannot force the model to use a specific tool via tool_choice. Anthropic-based models require tool_choice to be "auto" (or omitted) when thinking/reasoning is enabled.

What causes the error

Setting tool_choice to "required", "any", or {"type": "function", "name": "..."} while also enabling reasoning:
All of these tool_choice values are rejected when reasoning is enabled:
  • "required" — forces the model to call any tool
  • "any" — same as required
  • {"type": "function", "function": {"name": "..."}} — forces a specific tool

The fix

Use tool_choice: "auto" (or omit it entirely) when reasoning is enabled. The model will still call tools when appropriate — thinking models are highly capable of deciding when to use tools on their own:
If you absolutely need to force a specific tool, disable reasoning for that request. You can re-enable reasoning on subsequent turns once the forced tool call is complete.