Comparing Provider APIs: Anthropic, OpenAI, and Google
The same feature built against the three major APIs: where they agree, where they differ, and what that means for portability.
Sooner or later you'll call more than one model provider. Maybe a customer requires a specific cloud, a new model is better at one of your features, an outage forces a fallback, or you just want to know whether you're overpaying. The three major APIs, from Anthropic, OpenAI, and Google, look similar from a distance. Up close, they differ in where instructions go, how messages are shaped, how reasoning is controlled, what a finished response looks like, and how usage is reported.
In this lesson you'll build the same Deskmate feature, ticket triage with structured output, against all three APIs using their official TypeScript SDKs. Then you'll write a thin normalization layer so the rest of your app doesn't care which provider answered. By the end, you'll know which differences are cosmetic, which ones leak into your design, and what that means for portability.
Where the three APIs agree
Under the naming differences, all three providers expose the same core concepts. If you know one API well, you already know what to look for in the others:
| Concept | Anthropic (Messages API) | OpenAI (Responses API) | Google (Gemini API) |
|---|---|---|---|
| Instructions | system | instructions | config.systemInstruction |
| Conversation input | messages with user / assistant roles | input: a string or list of items | contents with user / model roles |
| Output length cap | max_tokens (required) | max_output_tokens | config.maxOutputTokens |
| Reasoning control | output_config.effort | reasoning.effort | config.thinkingConfig.thinkingLevel |
| Structured output | output_config.format | text.format | config.responseMimeType + config.responseJsonSchema |
| Why it stopped | stop_reason | status + incomplete_details.reason | candidates[0].finishReason |
| Token usage | usage.input_tokens / output_tokens | usage.input_tokens / output_tokens | usageMetadata.promptTokenCount / candidatesTokenCount |
| Official TypeScript SDK | @anthropic-ai/sdk | openai | @google/genai |
All three also support streaming, tool calling, image input, prompt caching in some form, and batch processing at a discount. The concepts transfer; the field names and the details don't.
OpenAI also still offers its older Chat Completions API, which many other providers and local servers imitate. The Responses API is OpenAI's primary interface today, so that's what this lesson uses.