Tool run API
LiveRun your own tools from your own code with a project API key, and read the result in the same request.
The tool run API runs one of your own tools with the inputs you send, and answers when the run is finished. It uses the same project API keys as the run API for agents.
- Only published tools run, always on their latest published version.
- A key reaches only its own project's tools. A tool in another project, or another workspace, answers
404. - Every run is recorded. It shows on the tool's Run tab as an API run, with its inputs, each step's result and its rupee cost. Secrets and inputs marked Hide in run logs are masked there.
- Platform limits still apply. If AI work is paused on the platform, or the daily spending limit is reached, runs are refused. A single run stops once it has spent ₹5.
Before you start
- Build and publish the tool. Its Run tab shows the endpoint and ready-to-use examples.
- An Owner or Admin creates an API key under Integrations, then API keys. Keep it on your server, never in a web page or a mobile app.
Run a tool
POST /v1/api/tools/{tool_id}/runs
Send the key as Authorization: Bearer dhk_… and the inputs as JSON, using the input keys from the builder:
curl -X POST "https://engine.dhanurai.com/v1/api/tools/ctl_.../runs" \
-H "Authorization: Bearer $DHANUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"inputs": {"order_id": "A1234"}}'
const res = await fetch("https://engine.dhanurai.com/v1/api/tools/ctl_.../runs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DHANUR_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ inputs: { order_id: "A1234" } }),
});
const run = await res.json();
import os
import httpx
run = httpx.post(
"https://engine.dhanurai.com/v1/api/tools/ctl_.../runs",
headers={"Authorization": f"Bearer {os.environ['DHANUR_API_KEY']}"},
json={"inputs": {"order_id": "A1234"}},
timeout=70,
).json()
The body has one field, inputs. Leave out optional inputs you don't have. Values are checked the same way as on the form: numbers can be sent as numbers or text, yes-or-no inputs as true or false, and JSON inputs as any JSON value.
The request waits for the run to finish, for up to 60 seconds. Set your client's timeout a little higher.
The answer
{
"run_id": "trn_...",
"tool_id": "ctl_...",
"version": 3,
"status": "done",
"output": {"status": "shipped", "eta": "2026-09-20"},
"error": null,
"error_code": null,
"steps": [
{"id": "get_order", "name": "Get the order", "status": "ok", "duration_ms": 412},
{"id": "summary", "name": "Write a status line", "status": "ok", "duration_ms": 950}
],
"cost_inr": 0.0412,
"duration_ms": 1391
}
| Field | Meaning |
|---|---|
status |
done when the tool finished, failed when it stopped |
output |
The tool's result: text or JSON, as set in its Output. null when the run failed. |
error |
Why the run stopped, in plain words, such as "Step 1 (Get the order): The site answered with status 404." |
error_code |
step (a step failed), cost_cap (the run's spending limit), time (the run took too long), paused or daily_cap (platform limits), internal (our error) |
steps |
The steps that ran, in order, with their status and how long each took |
cost_inr |
What the run cost in rupees (AI and connected-app use) |
A tool can end early on purpose, when a Condition step stops it. That still counts as done, with the condition's result as output.
Secret values never appear in the answer, even if another service sends them back.
Status codes
| Code | When |
|---|---|
200 |
The run finished. Check status: a run whose step failed also answers 200, with status: "failed". |
401 |
The key is missing, wrong or revoked. |
404 |
No tool with this id in the key's project. |
409 |
The tool isn't published yet. |
422 |
The inputs are wrong. detail lists every problem, such as "Fill in Order number." |
429 |
Too many requests with this key (30 runs a minute). Wait for the seconds in Retry-After. |
503 |
AI work is paused on the platform, or the daily spending limit was reached. The body has error_code paused or daily_cap. Try again later. |
504 |
The run took longer than 60 seconds and was stopped. |
Good practice
- Retry with care. A tool that changes data may have made some changes before it failed. Check the run on the Run tab, or in your other system, before running it again.
- One key per system, so you can revoke one without stopping the others.
- Keep secrets in tool secrets. Your code only sends inputs; the tool adds keys for the services it calls. See Tool secrets.
Last updated 24 September 2026
Something unclear or wrong? Tell us