API reference · v1
Workflows API
Build an image pipeline once on the Pincel canvas, then run it from your code — or let an AI agent run it for you. Same models, same credits, no UI required.
On this page
Overview#
A workflow is a graph of Pincel tools you assemble on the canvas: remove a background, drop the product into a generated scene, relight it, upscale it, export. Once it's saved, this API runs that same graph with whatever inputs you pass in.
https://pincel.app— base URL. All responses are JSON.- Runs are asynchronous: start a run, then poll it.
- Credits are charged per step, exactly as in the app. The same content-safety checks apply to every step.
- Outputs are temporary — deleted after 7 days. Add a Save to Library node to keep a result permanently.
- Pass an array to a List input and the workflow runs once per row — a whole product catalog in one call.
- Using an AI assistant? Connect it to the MCP server and every saved workflow shows up as a tool it can call.
Quickstart#
Three calls: find your workflow, run it, poll for the result.
curl https://pincel.app/api/v1/workflows \
-H "X-API-Key: $PINCEL_API_KEY"curl -X POST https://pincel.app/api/v1/workflows/$WORKFLOW_ID/run \
-H "X-API-Key: $PINCEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"inputs":{"upload-1":"https://example.com/product.jpg"}}'curl https://pincel.app/api/v1/runs/$RUN_ID \
-H "X-API-Key: $PINCEL_API_KEY"Authentication#
Send your key in the X-API-Key header. It's a UUID — copy it from your account page.
X-API-Key: 3f7a1c92-8e54-4b0d-9a6f-2c1e5d840b7aKeep the key server-side
A 401 means the key is unknown or was rotated; a zero balance answers 402 instead — see Credit balance. Credits — not a subscription — are what entitle you here.
Inputs & node ids#
A workflow's source nodes are its inputs, and you address them by node id. Ask the API what they are rather than guessing:
{
"id": "7c4f…",
"name": "Product shot cleanup",
"estimated_credits_per_run": 7,
"inputs": [
{
"nodeId": "upload-1",
"type": "image",
"cardinality": "single",
"required": true,
"hasStoredValue": false
}
],
"steps": [
{ "nodeId": "remove-bg-1", "tool": "remove-bg", "name": "Remove Background" },
{ "nodeId": "upscale-1", "tool": "upscale", "name": "Upscale" }
]
}| Field | Meaning |
|---|---|
nodeId | The key to use in your inputs object. |
type | image expects a public image URL; text expects a string. |
cardinality | single takes one value; list takes an array and runs a batch. |
hasStoredValue | Whether the saved workflow already has a value here. If true, you can omit it. |
Omitted inputs keep their saved values
Image URLs must be publicly reachable over http(s). Private and loopback addresses are rejected.
Endpoints#
| Method & path | Purpose |
|---|---|
GET /api/v1/workflows | List your workflows with inputs, steps and cost. |
GET /api/v1/workflows/:id | Describe one workflow. |
POST /api/v1/workflows/:id/run | Start a run, or a batch. |
GET /api/v1/runs/:runId | Poll a run. |
GET /api/v1/batches/:batchId | Poll a batch. |
List workflows#
Everything an agent needs to pick a workflow and fill it in.
{
"workflows": [
{
"id": "7c4f…",
"name": "Product shot cleanup",
"updated_at": "2026-07-25T10:02:11.000Z",
"estimated_credits_per_run": 7,
"inputs": [ /* … */ ],
"steps": [ /* … */ ]
}
]
}Describe a workflow#
The same shape for a single workflow — see Inputs & node ids.
Run a workflow#
POST /api/v1/workflows/:id/run with an inputs object. Returns immediately with a run id.
{
"inputs": {
"upload-1": "https://example.com/product.jpg",
"text-1": "on a marble surface, soft daylight"
}
}{
"run_id": "b81e…",
"status": "running",
"poll": "/api/v1/runs/b81e…"
}Poll a run#
status is running, succeeded, failed or canceled. outputs holds the end results — the steps nothing else consumes — which is usually what you want; steps exposes intermediates too. Video-producing steps (Image to Video) return .mp4 URLs with the same retention rules.
{
"run_id": "b81e…",
"workflow_id": "7c4f…",
"status": "succeeded",
"error": null,
"credits_used": 7,
"outputs": ["https://static.pincel.app/workflows/…/result.jpg"],
"steps": [
{
"node_id": "upscale-1",
"tool": "upscale",
"status": "succeeded",
"outputs": ["https://static.pincel.app/…"],
"error": null,
"credits_used": 4
}
]
}Poll a batch#
One entry per List row, each with its own status and results.
{
"batch_id": "3f0a…",
"status": "running",
"done": false,
"credits_used": 7,
"rows": [
{
"run_id": "…",
"index": 0,
"label": "sku-1.jpg",
"status": "succeeded",
"error": null,
"credits_used": 7,
"outputs": ["https://static.pincel.app/…"]
},
{
"run_id": "…",
"index": 1,
"label": "sku-2.jpg",
"status": "running",
"outputs": []
}
]
}Batch a catalog#
Add a List node to the workflow on the canvas, then pass an array to it. The whole pipeline runs once per row, rows are independent — one failure doesn't stop the others — and you poll a single batch id.
{
"inputs": {
"list-1": [
"https://example.com/sku-1.jpg",
"https://example.com/sku-2.jpg",
"https://example.com/sku-3.jpg"
]
}
}- Up to 25 rows per call.
- A text List (one prompt per row) works the same way — useful for generating variants of one asset.
- The whole batch is checked against your balance up front, so it won't die halfway with some rows already charged.
MCP server#
https://pincel.app/api/v1/mcp is this API reshaped for agents: every saved workflow is one MCP tool, with an input schema generated from its graph — one property per input node id, arrays for List inputs. Two extra tools, get_run_status and get_batch_status, cover the asynchronous part. Connect an assistant once and it can discover and run your pipelines without composing REST calls.
claude mcp add --transport http pincel https://pincel.app/api/v1/mcp \
--header "X-API-Key: $PINCEL_API_KEY"- Auth — the same API key, sent as
X-API-KeyorAuthorization: Bearerfor clients that only support bearer tokens. - Transport — stateless Streamable HTTP: one JSON-RPC message per POST, no sessions, no SSE stream.
- Waiting — a run tool waits up to ~50 seconds and returns the outputs directly; longer runs come back as
status: "running"with arun_idto poll viaget_run_status. - Credits & limits — every tool result includes
credits_remaining; the rate limits are the same buckets as REST (list → discovery, run → start, status → polling).
Inputs with saved values are optional
Polling & webhooks#
Poll every ~2 seconds. There are no delivery webhooks yet.
Polling also drives the work
Run outputs expire after 7 days
saved_outputs alongside the temporary outputs.Credit balance#
Every response tells you where your balance stands, so an unattended integration can warn its owner before runs start failing:
- Header
X-Credits-Remaining: 4821— on every request, including errors. - Field
credits_remaining— in every JSON body.
curl -si https://pincel.app/api/v1/runs/$RUN_ID \
-H "X-API-Key: $PINCEL_API_KEY" | grep -i x-credits-remainingWhen the balance reaches zero, requests answer 402 rather than 401, so you can handle it specifically — a 401 then means only that the key is wrong or was rotated.
{
"error": "Out of credits. Top up at https://pincel.app/billing to keep running workflows.",
"code": 402,
"credits_remaining": 0
}Rotating your key
Rate limits#
Credits are the real throughput limit — every run spends them. These limits exist to protect shared model capacity, to stop a retry loop from burning credits by accident, and to block key guessing. The same limits apply to every account.
| Bucket | Limit |
|---|---|
POST …/run | 60 / minute |
Polling (/runs, /batches) | 600 / minute |
Discovery (/workflows) | 120 / minute |
| Runs in flight at once | 75 |
- 60 starts/minute is ≥1,500 rows/minute when batched, so a real catalog job never touches it.
- Runs in flight is the limit that matters most: one request can start 25 runs, so it's checked before a batch begins.
- A
429carriesRetry-AfterandX-RateLimit-*headers. Back off rather than retrying immediately — the window is a rolling 60 seconds.
Need more throughput?
Errors#
| Code | Meaning |
|---|---|
400 | Bad input — unknown node id, wrong value shape, a private URL, over the 25-row batch limit, or a required input with no value. The response repeats inputs so you can see what is missing. |
401 | Missing, unknown or rotated API key. |
402 | Out of credits — the balance is zero. Includes credits_remaining so an agent can act on it. |
404 | Workflow, run or batch not found — or not yours. |
405 | Wrong method. |
429 | Rate limit or in-flight run cap reached. |
A run that can't be afforded in full is rejected up front with a message naming the shortfall, rather than dying halfway with some steps already charged. Content that fails moderation isn't an HTTP error: the step ends with status blocked and isn't charged.
FAQ#
Do I need a subscription to use the Workflows API?
No. Credits are what entitle you — you can buy a credit pack without subscribing and use the API the same way. Requests are rejected only when your balance reaches zero.
How much does a run cost?
Exactly what the same steps cost in the app: the sum of each step in the workflow. Call GET /api/v1/workflows to see estimated_credits_per_run before you run anything. Failed and content-blocked steps are not charged.
Can I run one workflow over many images at once?
Yes. Put a List node in the workflow and pass an array of image URLs to it. The workflow runs once per row, up to 25 rows per call, and you poll a single batch id for all of them.
How long do result URLs last?
Run outputs are temporary — they are deleted after 7 days, for every account. Download what you need, or add a Save to Library node to the workflow: whatever feeds that node is copied to permanent storage and appears in your Pincel Media Library.
How do I know when my credits are running low?
Every response includes your balance — an X-Credits-Remaining header and a credits_remaining field — so an agent or script can warn you before runs start failing. When the balance reaches zero, requests answer 402 instead of 401 so you can react to that case specifically.
Can I regenerate my API key?
Yes — there is a Regenerate key button on your account page. The old key stops working immediately, so update your integrations before rotating.
Can my AI assistant run workflows directly?
Yes — connect it to the MCP server at https://pincel.app/api/v1/mcp with your API key and every saved workflow appears as a callable tool, plus status tools for polling. Works with Claude Code, Claude Desktop and any MCP client that supports HTTP servers with custom headers.
Can I call this from a browser?
No — this is a server-to-server API. There is no CORS, because calling it from a browser would expose your API key to anyone who views the page.
Build your first workflow
Start from a template on the canvas, then call it from your code with the three requests above.