Skip to content

For agents

The caller of this API is a program, and increasingly the program is an agent: something that reads a catalogue, decides, calls, and has to know afterwards whether it worked and what it cost. This page is the map for that reader: which surface to use, the rules to follow, and the URLs that answer without a key.

Which door

Every surface reaches the same API with the same key. The question is what the agent has.

the agent hasusewhy
an MCP client and no shell — Claude Desktop, a hosted agent, a chat productthe MCP servernothing to install on the agent's side; hosted or local. Tool definitions are present on every turn
a shell — Claude Code, Codex, Cursor, an agent inside a repository or a terminalthe agent skill + the CLIlocal files and whole directories, batches, and a script the agent leaves behind that a person can read and run again. The skill loads only when a task needs it
its own runtime — a workflow engine, a backend, a cron joban SDK, REST or the n8n nodethe same ops, jobs and presets as typed clients; webhooks instead of polling
both MCP and the skill configuredthe skill says whichMCP when no local files or script are needed; the CLI otherwise

Where the doors differ in what they can reach — the rows that most often decide it:

CapabilityMCP serverCLI + skillSDKs · RESTn8n node
local filesthe local (stdio) server only, as file_paths; the hosted one takes urls or asset_idsfiles and whole directoriesa path or the bytesbinary data from the node before it
a result with nothing storedtransform on one file or URL with a deterministic opimagestep image resize and every other synchronous opimages.transform · POST /api/v1/images/transformStore Result off
cancel or resume a jobnoneimagestep jobs cancel · imagestep jobs resumejobs.cancel · jobs.resumenone
hear that a job endedwait on the call, then poll job_status--wait, or imagestep webhook createa webhook, checked with webhooks.verifythe ImageStep Trigger node
save a chain as a presetsave_presetimagestep preset createpresets.create · POST /api/v1/presets— (it runs presets)

The operating contract

One document, the same on every surface: GET https://api.imagestep.dev/api/v1/agent-guidelines (no key), the MCP resource imagestep://agent-guidelines — which the server also sends as its instructions when a session opens — and imagestep guidelines in the CLI. It is fetched live, so a client released months ago still reads today's wording. Its sections, in order, with what each asks:

rulewhat the agent does
Read the catalogue before you choose an opGET /api/v1/ops is the vocabulary and the parameter contract. An op that is not there does not exist; a parameter that is not there is a 400 invalid_param.
Price before you spendPOST /api/v1/jobs?dryRun=true is the exact cost of the exact body. sufficientCredit: false means stop and tell the person — no change to the request fixes an account.
A chain you ran twice is a presetSave it with POST /api/v1/presets and run it by slug@version; a consistent character or product is a preset with subjects, not a longer prompt.
Jobs own the retry; you do notAnything with a model in it is a job. A deterministic op may answer synchronously (its syncEndpoint). Every write carries an Idempotency-Key.
Branch on retryable, not on the status codeFix what param names; retry what is transient; resume a retryable failed job once; pace from RateLimit-Remaining.
References, not bytesUpload once or hand the service a URL, keep the asset id, hand on the publicUrl. An image in a context window is tokens spent on something the agent cannot use.
A missing capability is a report, not a detourPOST /api/v1/feedback with kind: capability_gap, and a word to the person — not a local image library quietly substituted.
Leave the human able to take overThe preset saved and named, the cost known before it was spent, the failure classified, the gap reported.

Read it once per session:

const { markdown } = await client.agent.guidelines();

The loop, in any surface

The rules above as calls — the same seven steps whichever door the agent came in by:

stepRESTCLIMCP
discoverGET /api/v1/opsimagestep ops list -o jsonresource imagestep://ops
get the input inPOST /api/v1/assets/upload · POST /api/v1/assets/from-urlimagestep asset upload · imagestep asset from-urlfile_paths or urls on transform and run_preset
pricePOST /api/v1/jobs?dryRun=trueimagestep jobs estimatedry_run
runPOST /api/v1/jobs with an Idempotency-Keyimagestep jobs submit --waittransform · generate · run_preset, with idempotency_key
waitwait on the submit, GET /api/v1/jobs/{id}?wait=, or a webhook--wait · imagestep jobs waitwait_seconds, then job_status
hand on the resultPOST /api/v1/assets/update with published: trueimagestep asset publishpublish (on by default) — each output comes back with its public URL
report a gapPOST /api/v1/feedbackimagestep feedback sendsend_feedback

Machine-readable faces

Everything below answers without a key, so an agent can go from one URL to a priced call without a person reading a docs page.

The vocabulary — the op catalogue, which needs no key:

const ops = await client.ops.list(); // [{ op, kind, params, defaultModel, syncEndpoint, example, … }]

And the site itself in one fetch, for an agent that starts from a URL: https://imagestep.dev/llms.txt — a static file, so it has no SDK or CLI form. Every docs page is also served as markdown at its own URL plus .md, and all of them together at https://imagestep.dev/llms-full.txt.

What the person sees

Every job an agent runs is on the console's /jobs page — what op, which preset version, which model, what it cost, which item failed and why — and every asset it made is on /assets with its lineage. Keys are issued and revoked on /keys; spend by op, key or day is /usage and GET /api/v1/usage, and every gap an agent reported with POST /api/v1/feedback is listed on the same page. The console exists for the two things an API cannot do — hand out a credential and let a person check what the program did — and nothing an agent needs is only there (the console, page by page).