Base path: https://api.1toolring.com/api/v1/tools
Auth: Authorization: Bearer <key> (or x-api-key: <key>). Discover, inspect and the runs list also accept a dashboard session JWT, so the console can browse the catalog. Price: per call, in credits (1 credit = Rp1), shown on every tool before you run it. Discover, inspect and run status are free.
The tool catalog holds thousands of third-party tools across SERP, web scraping, people and company enrichment, social, ecommerce, maps and SEO. It is searched live, so this page documents the routes and the pricing model rather than listing every tool.
The flow: discover, inspect, run
- Discover. Describe the job in plain words. You get tool ids, a short description and the price.
- Inspect. Read one tool’s
input_schemaand its exact price model before you spend anything. - Run. Send the input. Credits are held up front, the call runs, and the hold settles to the real cost. A slow tool answers
202with arun_idyou poll.
The same flow is available to agents as MCP tools (discover_tools, inspect_tool, run_tool, get_tool_run). See MCP.
Endpoints
| Method | Path | Price | Description |
|---|---|---|---|
| POST | /discover | free | Search the catalog by job. Body {query, limit?} (limit 1 to 20, default 10). |
| POST | /inspect | free | One tool’s detail: input_schema, price, notes, health. Body {tool} or {provider, endpoint}. |
| POST | /run | per the tool’s price | Run a tool. Body {tool, input}. 200 when it finishes in time, 202 while it runs. |
| GET | /runs/{run_id} | free | Status and result of one of your runs. Refreshes a running run before answering. |
| GET | /runs | free | Your runs, newest first. limit and cursor query parameters. |
Discover
curl -X POST https://api.1toolring.com/api/v1/tools/discover \
-H "Authorization: Bearer $TOOLRING_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"google search results for a keyword","limit":3}'
{
"data": {
"query": "google search results for a keyword",
"count": 3,
"results": [
{
"id": "dataforseo/serp/google-organic",
"provider": "dataforseo",
"provider_name": "DataForSEO",
"endpoint": "/serp/google-organic",
"description": "Live Google organic results for a keyword, location and language.",
"price": { "model": "per_call", "credits": 60, "usd": 0.0033 }
}
]
}
}
Values in the examples on this page are illustrative. Read the real price from discover or inspect.
Inspect
curl -X POST https://api.1toolring.com/api/v1/tools/inspect \
-H "Authorization: Bearer $TOOLRING_KEY" \
-H "Content-Type: application/json" \
-d '{"tool":"dataforseo/serp/google-organic"}'
{
"data": {
"id": "dataforseo/serp/google-organic",
"provider": "dataforseo",
"provider_name": "DataForSEO",
"endpoint": "/serp/google-organic",
"description": "Live Google organic results for a keyword, location and language.",
"summary": "Top organic results with title, URL, snippet and rank.",
"method": "POST",
"price": { "model": "per_call", "credits": 60, "usd": 0.0033 },
"input_schema": {
"body": {
"type": "object",
"required": ["keyword"],
"properties": {
"keyword": { "type": "string" },
"location_code": { "type": "integer" },
"language_code": { "type": "string" }
}
}
},
"notes": [],
"categories": ["serp", "seo"],
"tags": ["google", "search"],
"doc_url": "https://docs.dataforseo.com/",
"health": { "status": "ok", "p50_ms": 2100, "p95_ms": 5400 }
}
}
input_schema has up to three parts, each a JSON Schema: body (the JSON body), queryParams and pathParams. Send only the parts the schema declares.
Run
curl -X POST https://api.1toolring.com/api/v1/tools/run \
-H "Authorization: Bearer $TOOLRING_KEY" \
-H "Content-Type: application/json" \
-d '{"tool":"dataforseo/serp/google-organic","input":{"body":{"keyword":"kopi pontianak","language_code":"id"}}}'
A run that finishes in time answers 200:
{
"data": {
"run_id": "run_01JC8Q4Z6N4M2V9W3X7Y5T1R0P",
"tool": "dataforseo/serp/google-organic",
"status": "completed",
"output": { "items": [ { "rank": 1, "title": "...", "url": "..." } ] },
"provider_status": 200,
"credits_charged": 60,
"credits_held": 0,
"created_at": "2026-11-02T09:00:00Z",
"completed_at": "2026-11-02T09:00:03Z"
}
}
output is the tool’s answer, passed through as is. The X-ToolRing-Credits header on a finished run is the number of credits actually charged.
RunResult fields
| Field | Type | Description |
|---|---|---|
run_id | string | Your run id, e.g. run_<ulid>. |
tool | string | The tool id that ran. |
status | string | running, completed or failed. |
output | any | The tool’s answer, verbatim. |
provider_status | integer | The HTTP status the tool’s provider returned. |
provider_error | string | Short reason when the provider failed. |
credits_charged | integer | Credits actually charged (0 while running and on failure). |
credits_held | integer | Credits held while the run is in flight. |
created_at, completed_at | string | ISO 8601 timestamps. |
Async runs and polling
Scrapers and bulk enrichment can take longer than one request. Then /run answers 202 with status: "running" and the hold still in place:
{
"data": {
"run_id": "run_01JC8Q7B2K9D4F6H8J0L2N4P6R",
"tool": "apify/google-maps-scraper",
"status": "running",
"credits_held": 9000,
"created_at": "2026-11-02T09:05:00Z"
}
}
Poll until status is completed or failed:
curl https://api.1toolring.com/api/v1/tools/runs/run_01JC8Q7B2K9D4F6H8J0L2N4P6R \
-H "Authorization: Bearer $TOOLRING_KEY"
Every 3 to 5 seconds is a sensible interval. Polling is free. The hold settles when the run finishes, whether you poll or not: a background job also checks running runs. Only runs made by your own account are visible.
Pricing model
Every tool carries a price object:
| Field | Description |
|---|---|
model | per_call, per_result, per_unit, tiered or free. |
credits | Price per call, result or unit, in credits (1 credit = Rp1). Any non-free unit costs at least 1 credit. |
usd | The same price in US dollars, for reference. |
unit_label | What one unit is, for per_unit tools (for example 1,000 characters). |
flat_credits | A fixed fee on top of the unit price, when the tool has one. |
notes | Extra pricing detail, such as tier boundaries. |
How a run is billed:
- Hold, then settle. Before the call, 1ToolRing holds the most the run can cost.
per_callholds the price.per_result,per_unitandtieredhold an estimate from your input (fields such aslimit,maxItems,max_results,depthornum). When the run finishes, the hold settles to the real cost and the rest is released. - Failed calls cost 0. A provider error or a
failedrun releases the whole hold. You are charged nothing. - Run cap. A single run has a spending cap. If the estimate is above it, the run is refused with
400 RUN_TOO_LARGEbefore anything is held. Lower the result count or split the job. - Balance check. If your balance is below the hold, the run is refused with
402 INSUFFICIENT_CREDITSand nothing runs.
Credits come from the same prepaid wallet as every other 1ToolRing call. See Rate limits and credits and pricing.
Errors
Envelope: {"error":{"code","message"}}.
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | The body is malformed or input does not match the tool. |
| 400 | RUN_TOO_LARGE | The estimated cost is above the per-run cap. Nothing was held. |
| 401 | UNAUTHORIZED | Missing or invalid key. |
| 402 | INSUFFICIENT_CREDITS | The wallet cannot cover the hold. Carries balance, needed and topup_url. |
| 403 | TOOL_BLOCKED | This tool is not offered through 1ToolRing. Pick another from discover. |
| 404 | TOOL_NOT_FOUND | Unknown tool id. |
| 404 | NOT_FOUND | Unknown run, or the tool catalog is not enabled on this host. |
| 429 | RATE_LIMITED | Too many requests. Retry after a short wait. |
| 502 | UPSTREAM_ERROR | The tool network could not be reached. Nothing was charged. |
| 503 | TOOLS_UNAVAILABLE | Third-party tools are temporarily unavailable. Nothing was charged. |
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Credit balance is too low for this run.",
"balance": 40,
"needed": 60,
"topup_url": "https://app.1toolring.com/billing"
}
}
A provider failure inside a run is not an HTTP error: the run comes back with status: "failed", provider_status, a short provider_error and credits_charged: 0.