Call tools and use web search
Request only capabilities advertised for your model and complete the tool result cycle.
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.
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.
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:
{
"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:
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:
export UNLIMGPT_REQUEST_KEY="$(openssl rand -hex 16)"
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.