한국어

Run a saved flow by API or MCP

A flow you build on the workflows page can be exported (Export → Download flow) as a small JSON file. It holds the steps and their options only, never your files. The same flow then runs by API or from an AI assistant, with the same step rules and the same tool code as the page.

Where your files go

API: POST /v1/flows/run

curl -X POST https://toolsthatdontupload.com/v1/flows/run \
  -H "X-API-Key: YOUR_KEY" \
  -F 'flow={"schema":"ttdu.flow/v1","steps":[{"tool":"pdf.merge","scope":"all","options":{}}]}' \
  -F files=@a.pdf -F files=@b.pdf

Or send JSON: {"flow": {...}, "files": [{"name": "a.pdf", "base64": "..."}]}. Files run in the order you send them. The answer is JSON: {"ok": true, "steps": [...], "notes": [...], "outputs": [{"name", "mime", "size", "sha256", "base64"}]}. notes lists remarks from the steps, for example a file in which a masking step found nothing to hide; it is often empty.

Values given at run time (vars)

A flow can declare values that are filled in when it runs, such as a client name used in the output file name: "vars": [{"key": "client", "label": "Client"}] and a step with "outName": "{client}-merged". Send the values as a form field vars holding a JSON object (or a vars object in a JSON request). A var with "default": "today" gets the run date (YYYYMMDD) when you leave it out.

curl -X POST https://toolsthatdontupload.com/v1/flows/run \
  -H "X-API-Key: YOUR_KEY" \
  -F 'flow={"schema":"ttdu.flow/v1","vars":[{"key":"client","label":"Client"}],"steps":[{"tool":"pdf.merge","scope":"all","options":{},"outName":"{client}-merged"}]}' \
  -F 'vars={"client":"ACME"}' \
  -F files=@a.pdf -F files=@b.pdf

The result is named ACME-merged.pdf. If a declared var is missing, the answer is 422 with "code": "needs_input" and "details": {"reason": "vars", "missing": ["client"]}; a vars field that is not a JSON object gives 400. Through MCP, pass the same values as the vars argument of run_flow.

Run a single tool

There is no separate endpoint per tool: send a flow with one step. For example, rotate every page of each file by 90 degrees:

curl -X POST https://toolsthatdontupload.com/v1/flows/run \
  -H "X-API-Key: YOUR_KEY" \
  -F 'flow={"schema":"ttdu.flow/v1","steps":[{"tool":"pdf.rotate","scope":"each","options":{"angle":90}}]}' \
  -F files=@scan.pdf

"scope": "each" runs the tool on every file separately; "all" gives all files to the tool at once (as for a merge). The tool ids and their options are the ones the workflows page exports.

Limits and cost: a run counts as one file call, the same as the PDF endpoints: one of the 20 free file calls a day for a key (otherwise 60 credits), or one of 20 calls a day per IP address without a key. Up to 20 files and 15 MB in total (10 MB through MCP). A call counts even when the flow stops with an error.

Errors: 400 the flow is not ttdu.flow/v1, no files, or vars is not a JSON object; 413 over the size limit; 422 a step failed (the answer names the step and the reason) or a step needs a browser, such as image.batch (run that flow on the workflows page), or a var is missing (needs_input); 401, 402 and 429 as for the other endpoints.

OpenAPI description of this endpoint and the HWP endpoints: /openapi/files.json (OpenAPI 3.0).

MCP: run_flow

The MCP server (setup) has a run_flow tool with the arguments flow, files: [{name, base64}] and, for flows that declare vars, vars. It calls the same endpoint, with the same limits.

Same result in all three

In our test on 2026-11-06 the same nine flows gave byte-identical files on the workflows page, by API and by MCP: PDF merge, compress, fit to a size, page select, rotate, split, images to PDF, text from a Word file, and a PDF summary.

Offline on your own computers

A command line that runs the same flows with no network access is available to businesses. Contact us.