← Blog

Claude API Function Calling vs OpenAI Functions

2026-10-16 · 5 min read · SubToAPI Team

Claude API function calling (called tool use in Anthropic's docs) and OpenAI's function calling solve the same problem — letting a model call external code instead of guessing at an answer — but they differ in request structure, response format, and how they handle multiple tool calls in a single turn. If you're deciding which to build against, or porting an integration from one to the other, the differences matter more than the marketing copy suggests.

The short answer: both let you define functions with JSON Schema parameters, both return structured arguments instead of free text, and both support streaming partial results. The real differences are in field naming, how parallel calls are represented, and how strict the model is about matching your schema. Below is a side-by-side breakdown so you can pick the right approach or avoid surprises when switching providers.

Request structure: tools vs functions

OpenAI's chat completions API uses a tools array with type: "function", and each tool has a function object containing name, description, and parameters (JSON Schema).

{
  "model": "gpt-4o",
  "messages": [{"role": "user", "content": "What's the weather in Lisbon?"}],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    }
  ]
}

Claude's Messages API also uses a tools array, but the schema lives at the top level of each tool object — no nested function wrapper:

{
  "model": "claude-sonnet-4-5",
  "max_tokens": 1024,
  "messages": [{"role": "user", "content": "What's the weather in Lisbon?"}],
  "tools": [
    {
      "name": "get_weather",
      "description": "Get current weather for a city",
      "input_schema": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  ]
}

The field is called input_schema in Claude versus parameters in OpenAI — a small but easy-to-miss detail when porting code. If you're calling Claude through SubToAPI, the request shape is identical to the native Messages API, so existing Claude tool definitions work unchanged — see the tools docs for the full reference.

How tool calls come back

OpenAI returns tool calls inside the assistant message as a tool_calls array, each with an id, a function.name, and a function.arguments string that you need to JSON.parse yourself.

Claude returns tool use as a content block with type: "tool_use", including an id, name, and an already-parsed input object — no manual JSON parsing required:

{
  "role": "assistant",
  "content": [
    {
      "type": "tool_use",
      "id": "toolu_01A09q90qw90lq917835lq9",
      "name": "get_weather",
      "input": { "city": "Lisbon" }
    }
  ]
}

This is a minor convenience, but it removes a common source of bugs: malformed JSON strings from function.arguments that fail to parse when the model produces slightly invalid output.

Sending results back

Both APIs require a round trip: you execute the function, then send the result back as a new message so the model can continue. OpenAI expects a message with role: "tool" and a matching tool_call_id. Claude expects a tool_result content block inside a user message, referencing the original tool_use_id:

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "18°C, partly cloudy"
    }
  ]
}

Conceptually the same pattern — model calls, you execute, you report back — just different envelope names. If you're building this flow against SubToAPI, the request/response shapes follow the Messages API exactly, so any Claude-native tool-use code works with no translation layer.

Parallel tool calls

Both providers support calling multiple tools in one turn. OpenAI returns multiple entries in tool_calls. Claude returns multiple tool_use blocks in the same content array. The practical difference is minimal — in both cases you loop over the returned calls, execute each, and send all results back together before the next model turn. Where Claude tends to differ is in being more conservative about calling tools in parallel unless your prompt or schema descriptions make it clear parallel execution is safe and independent.

Forcing a specific function

OpenAI lets you force a specific function via tool_choice: {"type": "function", "function": {"name": "get_weather"}}. Claude has an equivalent tool_choice parameter with {"type": "tool", "name": "get_weather"}, plus an "auto" mode (default) and a "any" mode that forces some tool call without specifying which one. OpenAI doesn't have a direct equivalent to "any" — you either let the model choose freely or pin an exact function.

Streaming tool calls

Both APIs stream tool call arguments incrementally as the model generates them, which matters for latency-sensitive apps that want to start preparing a function execution before the full arguments arrive. OpenAI streams tool_calls deltas with partial arguments strings you concatenate. Claude streams input_json_delta events inside content_block_delta that you accumulate into the final input object. If you're already consuming SubToAPI's SSE stream for text, tool-use streaming follows the same event pattern — details are in the streaming docs.

Which one should you build for first?

If you're starting fresh and only need one provider, pick based on model quality for your use case, not API ergonomics — both function-calling implementations are mature enough for production. If you want the option to switch models without rewriting your tool-calling logic, abstracting behind your own thin wrapper function (one that maps your internal tool schema to either provider's format) pays off quickly. Teams using SubToAPI to front their Claude usage get a stable HTTPS endpoint and usage metadata per key, which makes it easier to compare tool-use costs and latency against an OpenAI-based path side by side without touching production code paths.

Getting started

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Book a meeting for 3pm"}],
    "tools": [{
      "name": "create_event",
      "description": "Create a calendar event",
      "input_schema": {
        "type": "object",
        "properties": {"time": {"type": "string"}},
        "required": ["time"]
      }
    }]
  }'

Sign up at /signup to get an API key and test this against your own tool schema — the quickstart walks through the first request end to end.

Questions

Is Claude's tool use the same as OpenAI function calling? Functionally yes — both let a model select a function and return structured arguments. The field names differ (input_schema vs parameters, tool_use vs tool_calls), but the request/response/round-trip pattern is conceptually identical.

Does Claude parse function arguments as JSON automatically? Yes. Claude's tool_use blocks return an already-parsed input object, while OpenAI returns arguments as a raw JSON string you must parse yourself.

Can I force Claude to call a specific tool like OpenAI's tool_choice? Yes, Claude supports tool_choice with {"type": "tool", "name": "..."} to force a specific function, plus "auto" and "any" modes — see the tools documentation for the full parameter list.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →