Every major API accepts a messages array and something that looks like a tool definition, so it is tempting to treat them as interchangeable. In practice each provider has its own opinion about what "valid" means, and those opinions disagree with each other and sometimes with the JSON Schema spec. A team running tens of thousands of calls a day across Anthropic, Google and OpenAI reported accumulating provider-specific patches precisely because the surface convergence is only skin deep: Gemini rejects an array whose items is an empty schema, no major provider accepts a top-level $ref, and OpenAI's own Chat Completions and Responses APIs nest the same structured-output request in two different shapes (FutureSearch on provider quirks).
The structural differences go deeper than validation. The system prompt is a top-level field in three of the four big request formats and a message role in OpenAI Chat Completions, the conversation container is messages[] in one, contents[] in another and input plus a previous-response identifier in a third, and Bedrock routes anything model-specific through a separate field rather than the unified inference parameters (cross-provider parameter reference). A router that forwards a body unchanged is therefore not "provider agnostic". It is a body shaped for whichever family the author tested against last.
There is also a failure mode that is not a 400 at all. When a downstream tool renamed a response field and the agent's parser raised on it, the retry policy classified the parse error as transient, retried three times, and the fallback degraded so gracefully that users got a worse answer rather than an error. The retry budget dashboard stayed green the whole time because retries were failing within budget, not exhausting it (the tool schema migration writeup). Shape mismatches can be silent on the request side and loud on the response side. Your fixture matrix has to cover both.



