Find, describe, invoke
Find and describe never execute a provider call and work without a key. Invoke needs a credential with the invoke scope.
Tools are addressed by tool_id
A tool id names one provider endpoint, for example anyapi.twitter.search or hunter.email_verifier. There are no domains, capabilities or routes to resolve first, and AgentRouter does not silently switch providers for you: the agent chooses the tool, and the receipt names the provider that ran.
Find
queryis a short task description (up to 500 characters). Matching is by keywords over tool ids, titles, tags, descriptions, use cases, and category/group names and aliases.- Optional filters:
provider,category_ids(any),group_ids(any),tags(all must match),include_unavailable(tools in an outage are hidden by default). matchisexact,partialornone. Withnone, record the gap with feedback (kind: tool_request) instead of forcing an unrelated tool.- Each candidate includes
required_inputs,price(summary,price_multiplier,free) andhealth(unknownmeans too few recent runs, not unavailable).
Browse the two-level catalog
GET /v1/catalog returns enabled tools plus groups and categories. Groups are top-level themes such as Social and GTM. Categories are second-level entries such as LinkedIn, Google Search, People Profiles or Web Search. There is no separate platform field. A category’s parent_ids refer only to groups.
Tools include category_ids and derived group_ids in catalog, find and describe responses. A tool may appear in more than one category; tool_count counts each tool once per category/group. Empty entries are omitted. GET filters use comma-separated IDs, for example /v1/catalog?category_ids=linkedin,people-data&provider=anyapi. Filters from different dimensions intersect.
CLI: agentrouter find "person profile" --category linkedin --group gtm. MCP find_tools uses the same category_ids and group_ids arrays. Tags remain search keywords; they do not create categories or another navigation level.
Describe
The response is the tool’s contract:
Health covers the full seven-day window in health.window, using each run’s finish time. samples is the number of completed, failed and timed-out logical calls; blocked requests and cancellations are excluded. success_rate is completed calls divided by samples, including legitimate empty results as completed calls.
health.latency reports exact nearest-rank p50 and p95 execution times for successful calls only. Its own samples excludes missing or invalid durations. Execution time includes asynchronous processing and polling waits, but excludes final settlement and delivery to the client. The flat p50_ms and p95_ms fields remain as aliases of these successful-call percentiles.
Health is calculated from stored runs on demand and cached for 60 seconds. computed_at and the window bounds identify the snapshot; reading health never calls the provider. Empty-result detection and the legacy empty_rate remain endpoint-specific.
You can reuse a describe result for many calls. Describe again when invoke reports PRICING_CHANGED or TOOL_VERSION_CHANGED.
Invoke
Clients cannot send prices or multipliers; a request that includes them is rejected with PRICE_NOT_CLIENT_SETTABLE.
Invoke returns a Run. HTTP 200 means it finished (completed, failed, stopped or timed out), 202 means it is still running on the server, 402/409 mean it was blocked before execution and not charged.
Choosing between tools
When several tools fit, the agent decides within the task and the user’s spending rules: compare fit, the inputs you already have, max_per_call_usd and health. Do not stop just to ask the user to choose a provider. Respect a tool or entry the user named, and tools the user already has for the same job.