The console
The API is the product; the console is where a person does the few things a program cannot do for itself — take a key, pay — and checks what a program did. Everything else it shows is a reading of the same API your keys call, so nothing an automation needs is only here.
The pages
Sign in and the rail on the left lists them in three groups, by what you came to do: Account, the two things no API call can hand you — a key, and the money behind it; Build, what you set up for a program to run; and Activity, what your keys then did. Docs and your own account sit at the foot. Each row says what the page holds, why it is a page at all, and the calls it sends.
| page | what it holds | why it is in the console | what it calls |
|---|---|---|---|
| API keys | Create and revoke keys. A key is shown once, when you create it. | issuing a credential: a key is shown once, and something has to show it to a person — beside the lines that put it into the CLI, an MCP client or n8n | GET /api-keys sign-in onlyPOST /api-keys sign-in onlyDELETE /api-keys/{keyId} sign-in only |
| Usage & billing | What your keys spent, your plan, your credit balance and how you pay. | paying: a card, a plan change and a top-up need a person and Stripe — and reading back what your keys spent and what your agents reported | GET /usageGET /feedbackPOST /credit/checkout sign-in onlyPOST /plan/upgrade sign-in onlyGET /payment/customer-portal sign-in only |
| Playground | Stage, upload, dry-run, submit, poll — exactly the calls the SDK makes. | trying an op or a preset on real images before writing code — it sends the requests a program sends, and prints each one for every surface | GET /opsPOST /jobsPOST /images/transformPOST /presets |
| Presets | The named, versioned chains your agents pin — what each runs, and how much. | keeping what the tuning produced — what each preset runs and how often it ran — and the calls that are a decision rather than an edit | GET /presetsPUT /presets/{slug}DELETE /presets/{slug}DELETE /presets/{slug}/versions/{version} |
| Webhooks | Signed job events, delivered to your HTTPS endpoint. | registering where signed job events go, showing a new secret once, and reading what was delivered | POST /webhook-endpointsPOST /webhook-endpoints/{id}/testPOST /webhook-endpoints/{id}/rotate-secretGET /webhook-endpoints/{id}/deliveries |
| Jobs | What your keys ran: each job, its items, what it cost and why it failed. | checking what a program did: every job your keys ran, its items, its cost and why an item failed — and cancelling or resuming one | GET /jobsGET /jobs/{id}POST /jobs/{id}/cancelPOST /jobs/{id}/resume |
| Assets | Everything you uploaded or generated — publish one for a stable CDN URL. | checking what a program made — every image and the run behind it — and acting on a batch of it | GET /assetsPOST /assets/updatePOST /assets/deletePOST /jobs |
| Account | Who you are in this console, and what we hold about you. | who you are signed in as, a copy of the data held about you, and deleting the account | POST /gdpr/export sign-in onlyPOST /gdpr/delete sign-in only |
A call marked sign-in only answers to a person's session and never to an API key — it is the reason that page exists. The rest are the endpoints your keys call, linked to their reference.
Keys and billing
API keys creates a key and shows it once, with the lines that put it where it goes — the environment variable, an MCP client's config, the n8n credential — and lists each key with when it was last used. None of it is in the API a key reaches: a key can revoke itself (DELETE /api/v1/api-keys/self) and nothing more, so a leaked key cannot mint another.
Usage & billing has three tabs. Usage is what your keys spent, by op, by key or by day — the same GET /api/v1/usage a program can read — and every gap an agent reported with POST /api/v1/feedback. Credits is the balance and its ledger: a top-up is charged to the saved card on the spot, or goes through Stripe Checkout when there is none, and auto top-up adds a fixed amount whenever the balance drops below a threshold, up to a monthly cap. Billing is the plan, the card and the invoices: a paid plan changes in place after showing you the prorated amount, leaving Free goes through Checkout, cancelling takes effect at the end of the period and can be undone until then, and the card itself is managed in Stripe's billing portal.
Account is who you are signed in as; its Privacy & data tab exports what is held about you and deletes the account (privacy).
The playground
The playground is drawn as the step it stands in for: your images on the left, the ImageStep node you set up in the middle, the results on the right. The node's boxes are read from the op's own catalogue entry — its type, its default as the placeholder, its description as the hint — and an AI op's model is the list of models that run that op, each with what one image costs on it. Every step also opens as the JSON it writes.
Inputs are files you drop in, URLs the service fetches, or assets you pick from your library — mixed, up to 12 of them, which is one batch. A file or URL is stored as an asset the moment you add it, so the picture you see is the one the service made of it, and it stays stored in a playground collection; a job's results land in the collection of the image each came from. Under the buttons the page offers to delete what it stored since you opened it — that much and no more — and links to the rest of the collection on Assets. Emptying the input list deletes nothing.
| you press | the page sends | what happens |
|---|---|---|
| add a file, or a URL | POST /api/v1/assets/stage-upload → PUT → finish-upload, or POST /api/v1/assets/from-url | stored at once, in the playground collection |
| Price it | POST /api/v1/jobs?dryRun=true | the body the run will send; a chain is priced step by step |
| Run | POST /api/v1/jobs, then GET /api/v1/jobs/{id} until it settles | an op, a preset or a chain, over every image as one job; a run that outlasts the page's patience carries on, and Jobs follows it |
| Run now | POST /api/v1/images/transform | one image and a deterministic op only: the result comes straight back and nothing is stored or published |
| Save… | POST /api/v1/presets or PUT /api/v1/presets/{slug} | a new preset of your own, or the next version of the one you opened |
| Publish, on a result | POST /api/v1/assets/update | a stable publicUrl |
Which lane a deterministic op takes is your choice between Run now and Run as a job; an AI op, a preset with a model in it, or more than one image is always a job (synchronous ops). A price is a button of its own, not a step of Run. The results mirror the inputs — the same squares in the same order, numbered, held open from the moment you press Run — and an image whose run failed keeps its square, with the reason listed under the grid. A batch goes on as a batch: every result back in as the next run's input, or out as one .zip numbered like the squares, beside a results.json that names the items which made no picture.
Beside the canvas — docked at the bottom or on the right, resized by its edge, folded away when you do not need it — is the request itself, with the ids and parameters of the run in front of you and the dry run while a price is on screen. One op is written for JavaScript, Python, the CLI, curl, an MCP tool call and an n8n workflow; an unsaved chain has no MCP or n8n form. It is the code the ops pages show, so what you copy is what the page just sent.
The node holds one chain of steps, and whether it runs as an op, a preset or a chain is what those steps work out to, not a switch. Open a saved preset — a built-in or your own, at any stored version — and its steps are the chain; left as loaded, it runs as that slug@version, exactly what a program will run a thousand times. Change a step or add one and the chain runs as it stands; saving is what gives it a name and a version for a program to pin. An earlier version saved as it stands becomes the current one — the same revert Presets offers. A step of a longer chain can be run on its own, and Use as input makes a result the next run's input, which is how a chain is tuned before it is saved. Listing, renaming and deleting presets are on Presets; importing one is the API's and the CLI's (managing presets).
Every record of a run opens here on that run's inputs: a job on Jobs offers to try the same op — or the same preset at the version that ran — on the same source images, and each of its results and every image on Assets offers to try an op on that one image. The link carries ids and the op or preset name, never parameters or a prompt.
Presets and webhooks
Presets lists each preset with the steps it runs now, how many versions it keeps and how often it ran — the runs still on record, since a job's record expires with what it made. Writing steps is the playground's; this page holds the calls that are a decision rather than an edit, each with what it costs said before the button: renaming the slug programs pin, reverting to a stored version (which becomes the next version — nothing is lost), deleting a preset, and deleting one old version, after which slug@N answers 404 preset_not_found. A preset holds at most 50 versions; a save past that is refused rather than trimmed, and this page — where an old version can be deleted — says so when one gets there (versions).
Webhooks registers an endpoint — its URL, the events it wants, a label — and shows its signing secret once. Each row says what it actually receives and whether it is on; opening one reads its deliveries: delivered, retrying and when, queued, or given up. From there you send a test delivery, rotate the secret (shown once again), change the label or the events, turn a disabled endpoint back on, or delete it. The URL is not editable: register the new one, test it, then delete the old. Signing, retries and auto-disable are on webhooks.
Checking what a program did
When an agent or a workflow runs on your key, Jobs is the record: the op or the preset and its version, the model, what each item cost and, for a failed item, what went wrong and whether a retry can help (jobs). A job still running can be cancelled from there, and a failed one resumed — the same calls a program makes.
Assets shows what it made. Open one image and the panel beside it names the run behind it — the job, the op or the preset at the version that ran, the model, and the image it started from, one click away — next to what ingest measured of the result, the labels a program attached, the fingerprints that say whether two images are the same, everything the file says about itself, and the date the asset is deleted on. That panel opens wherever an image is shown — a job's inputs and results, an image the playground took in or handed back, the asset another one was made from — over the page you are on.
What you find there you can act on as a batch. Tick the images, shift-click a run of them or drag a box across the grid, then: run one op or one saved preset over all of them — one job, one item per image, priced with a dry run before the button that spends it is enabled; move them into a collection or out of one; replace their tags (the dialog shows the list every selected asset will carry, because the endpoint replaces rather than adds); publish them and copy their public URLs, one per line, or unpublish them; download them — one image is one file, several are one .zip with a manifest naming any whose bytes could not be read, and a selection too big for a browser to zip says so and sends you to the CLI; or delete them, which is final: there is no trash.
The filter above the grid is the call itself: GET /api/v1/assets with a chip per query parameter, and the same filter written underneath in English. Its menu is generated from this API’s own document, so every filter you click is a parameter you can write. collections, beside the menu, opens your collections — how many are in each and when each last grew, and how many are in none — and picking one puts it on the line as a collection chip, which opens the same list from then on. The list renames a collection too; renaming onto a name that already exists is a merge, and it says so, with the number the result will hold, before the button. Copy as gives the filter as a JavaScript or Python call, a CLI command, the URL, a curl, or the arguments for the MCP search_assets tool — a surface with no name for one of your filters gets no tab rather than a call that asks a different question. Paste a request takes a URL, a query string or the curl line out of your code and shows that call’s result, naming any parameter it did not apply — usually the answer to “why does my workflow find nothing”.