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, dataforseo, tavily or tinyfish.
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.