> ## Documentation Index
> Fetch the complete documentation index at: https://docs.iotools.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Chaining tools

> Feeding one tool's output into the next

Tool outputs are plain strings keyed by name, so piping one into another needs no glue beyond reading the right field.

## Decode, then format

Take a base64-encoded JSON payload and produce something readable:

```javascript theme={"system"}
const { decoded: json } = await runTool("base64-decode", {
  base64String: encodedPayload,
});

const { formatted: pretty } = await runTool("json-formatter", {
  json,
  indent: "2",
});
```

Two calls, two charges — each one billed at your plan's minimum, since neither tool carries a weight above it.

<Note>
  Each hop costs credits and a round trip. Many tools already do the composite job in one call — [`GET /v1/tools/search`](/api-reference) is free, so check before building a pipeline.
</Note>

## Validate before you spend

For expensive tools, run a cheap validator first rather than paying for a failure you could have predicted:

```python theme={"system"}
# Is this even valid JSON? Bad input fails validation, and failed
# calls are refunded — so the check only costs anything when it passes.
try:
    run_tool("json-formatter", {"json": payload})
except RuntimeError as e:
    if e.args[0].startswith("validation_error"):
        return "not JSON"
    raise

# only now, the expensive one
run_tool("json-schema-generator", {"jsonInput": payload})
```

Failed calls are refunded, so this is about your error handling rather than saving credits.

## Batching

There is no batch endpoint. Call the tool once per item, respecting the [rate limit](/concepts/rate-limits):

```javascript theme={"system"}
// 60 req/min on the free tier
async function mapWithLimit(items, limit, fn) {
  const out = [];
  for (let i = 0; i < items.length; i += limit) {
    out.push(...(await Promise.all(items.slice(i, i + limit).map(fn))));
  }
  return out;
}

const results = await mapWithLimit(urls, 5, (url) =>
  runTool("url-parser", { urlToParse: url }),
);
```

Watch `credits_remaining` on each response — it is the cheapest possible progress meter.
