Call tools and use web search

Request only capabilities advertised for your model and complete the tool result cycle.

Set BASE_URL to your HTTPS API origin without a trailing slash or /v1, and pass API_KEY from your credential store. OpenAI-compatible SDKs use ${BASE_URL}/v1; Anthropic-compatible SDKs use BASE_URL.

Start with the model catalog. A tool or search request is accepted only when the model, plan and selected API endpoint support it. Unsupported capabilities fail before execution.

Call a function

bash
printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    -d '{
  "model": "gpt-5.6-sol",
  "input": "Check record 42.",
  "tools": [
    {
      "type": "function",
      "name": "lookup",
      "parameters": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      }
    }
  ],
  "max_output_tokens": 64,
  "stream": false
}'

If the model returns a function call, execute your own lookup function. Send its output back as a function_call_output with the returned call_id in the next turn; do not claim the function was executed until your application actually ran it. The visible result is then a later assistant response. Tool arguments are untrusted input: validate them in your application.

Complete the tool cycle

In the first response, find an output item with type: function_call. It contains name, arguments, and call_id. Parse the JSON in arguments, validate it against your schema, and execute lookup in your application. Suppose it returns {"status":"active"}. The next request includes the original question, the function call, and its result with the same call_id:

json
{
  "model": "gpt-5.6-sol",
  "input": [
    { "role": "user", "content": "Check record 42." },
    {
      "type": "function_call",
      "call_id": "call_018f3f407b447cc4b8ba3f62",
      "name": "lookup",
      "arguments": "{\"id\":\"42\"}"
    },
    {
      "type": "function_call_output",
      "call_id": "call_018f3f407b447cc4b8ba3f62",
      "output": { "status": "active" }
    }
  ],
  "tools": [
    {
      "type": "function",
      "name": "lookup",
      "parameters": {
        "type": "object",
        "properties": { "id": { "type": "string" } },
        "required": ["id"]
      }
    }
  ],
  "max_output_tokens": 64,
  "stream": false
}

Save this JSON as tool-result.json. The question, arguments, and call_id illustrate the shape: in the real file, use values from your first response and your function's actual result. If the first response has no function_call, skip the second request. Send the prepared file with the same Bearer key:

bash
printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    --data-binary @tool-result.json

If the first response has several parallel calls, execute each one and include every matching function_call and function_call_output item in a single next request. The resulting response either completes the turn with text or requests more tools; in the latter case, repeat the cycle. previous_response_id is not supported, so include the needed history in input. The next request is a separate generation and may consume credits; check the operations in API Activity.

For native web search, Responses accepts a web_search tool; Chat Completions uses web_search_options, and Messages uses its web_search server tool. Before calling, check the chosen model's capabilities.webSearch in the catalog and your plan's access. Search starts a paid generation.

In a shell with OpenSSL, generate one idempotency key, then send a bounded streamed Responses request:

bash
export UNLIMGPT_REQUEST_KEY="$(openssl rand -hex 16)"
bash
test -n "${UNLIMGPT_REQUEST_KEY:-}" \
  && printf 'Authorization: Bearer %s\n' "$API_KEY" \
  | curl -q -H @- -i -N "$BASE_URL/v1/responses" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $UNLIMGPT_REQUEST_KEY" \
    -d '{
  "model": "gpt-5.6-sol",
  "input": "Find the official UnlimGPT website and cite the source.",
  "tools": [
    {
      "type": "web_search"
    }
  ],
  "max_output_tokens": 256,
  "stream": true
}'

If gpt-5.6-sol is not available to your key, choose a catalog model with capabilities.webSearch: true. When the answer cites a source, inspect response.output_text.annotation.added and the final output annotations for its URL and location in the text. The response.web_search_call.* events are optional: handle them when present and do not treat their absence as an error. Treat both URL and retrieved text as untrusted source data; a search event alone does not prove the answer is correct. Require response.completed and the final [DONE] before marking the stream successful. For a retry, run only the second block with the same key and unchanged body; a new key may start another generation. For Chat Completions and Messages, parse the chosen protocol's final response; do not expect Responses event names.