Request
curl -X POST https://api.toolrouter.com/v1/tools/call \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tool": "web-search",
"skill": "search",
"input": { "query": "model context protocol spec", "num": 3, "provider": "serper" }
}'The input object is the skill's own JSON Schema: query is required, num, country, language, page, location, domains, timeRange and provider are optional, and provider accepts serper, brave, exa, serpapi or tavily.
Response
Field names are the real ones; the values are illustrative.
{
"id": "call_abc123",
"status": "success",
"output": {
"provider": "serper",
"provider_selection": "Serper is the default Google search provider.",
"request_id": "req_...",
"organic": [
{ "title": "Specification - Model Context Protocol", "link": "https://modelcontextprotocol.io/specification", "snippet": "..." }
]
},
"usage": {
"cost": 0.0105,
"currency": "USD",
"credits_remaining": 9.99,
"raw_cost": 0.01,
"markup": 1.05
},
"meta": { "tool": "web-search", "skill": "search", "latency_ms": 1234 }
}Every skill answers in that envelope: output is the skill's own schema, usage is what the call cost and what is left, meta names the tool, the skill and the latency. A failed call returns "status": "error" with an error code and message inside output, and is not billed — usage.cost is zero.