Submitting Work
There are two ways to submit a workflow:
- Generic —
POST /v2/consumer/workflowswith astepsarray and polymorphic$typeon each step. Use it to chain steps, mix step types, attach callbacks, tags, metadata orupgradeMode, or when your SDK handles the discriminator itself. - Per-recipe —
POST /v2/consumer/recipes/{recipe}with a single typed body (no$type). Each recipe wraps a single-step workflow. Use it when you only run one step type and want the simplest typed body — e.g.InvokeChatCompletionStepTemplate,InvokeComfyStepTemplate, etc.
The generic path returns a Workflow; a recipe returns only its step's output. You can mix them freely.
The generic path
POST https://orchestration.civitai.com/v2/consumer/workflows?whatif=false&wait=60
Authorization: Bearer <your-token>
Content-Type: application/json
{
"steps": [
{
"$type": "imageGen",
"input": {
"engine": "flux",
"prompt": "A cat astronaut floating through neon space",
"width": 1024,
"height": 1024
}
}
]
}Workflow-level body fields
Everything in the table lives alongside steps. See the full WorkflowTemplate schema for types.
| Field | Purpose |
|---|---|
steps | Required. One or more step objects, each with its own $type and input. |
callbacks | Webhooks for lifecycle events — see Results & webhooks. |
tags | Indexed string tags for later lookup via QueryWorkflows. Great for tenant / campaign / user IDs. |
metadata | Arbitrary JSON attached to the workflow. Not indexed — use for notes, correlation IDs, UI hints. |
arguments | Values steps can read via { "$ref": "$arguments" } — see Workflow arguments. |
allowMatureContent | Controls mature-content gating and which Buzz currency pays — see Payments (Buzz) below. |
experimental | Marks the workflow as experimental; may relax some guardrails. |
upgradeMode | How to handle a workflow paid with blue/green Buzz that turns out to produce mature content — see Payments (Buzz). |
currencies | Restrict which Buzz currencies may settle this workflow (see Payments (Buzz)). |
tips | Optional tip amount attached to the workflow. |
Query parameters
| Param | Default | Purpose |
|---|---|---|
wait | 0 | Seconds to block waiting for the workflow to finish; keep it below your HTTP client's timeout. If it is still running then, you get a 202. |
whatif | false | If true, validates and resolves the workflow (provider, estimated cost, required resources) without actually running it. Great for CI smoke tests and cost previews. |
hideMatureContent | false | If true, mature blobs on the response won't include a url. Useful for rendering in user-facing UIs without re-checking policy per-blob. |
Status codes
| Code | Meaning |
|---|---|
200 OK | The workflow reached a terminal state within your wait budget. |
202 Accepted | The workflow is still running. The body is the current workflow; continue via webhooks or GetWorkflow. |
400 Bad Request | Body failed validation — see Errors & retries for the response shape. |
401 Unauthorized | Missing or invalid bearer token. |
403 Forbidden | Token is valid but not allowed to use this recipe / resource / mature content flag. |
429 Too Many Requests | Rate limited. Wait for the Retry-After seconds, then retry — see Rate limits & quotas. |
Payments (Buzz)
Workflows are paid for with Buzz, Civitai's on-platform currency, from the balances on your civitai.com account; you never pass dollar amounts in the API. There are three currencies:
| Currency | Earned / bought | Valid for |
|---|---|---|
Blue (blue) | Earned by interacting on civitai.com | SFW workflows only |
Green (green) | Purchased | SFW workflows only |
Yellow (yellow) | Purchased | SFW and NSFW workflows |
Default charging
If you don't set currencies, the orchestrator charges your account in order blue → green → yellow, splitting across currencies if needed (all your blue first, the remainder from green, then yellow).
Restricting to specific currencies
Set currencies to limit which accounts can settle the workflow:
{
"steps": [ /* ... */ ],
"currencies": ["green", "yellow"]
}Only currencies you list will be drawn on. If none of them cover the cost, the submission is rejected with a payment error.
Mature content and currency interaction
- Setting
allowMatureContent: trueforces payment in yellow Buzz (the only NSFW-capable currency). - Setting
allowMatureContent: falserestricts to SFW and allows blue/green (plus yellow) to pay. - Leaving
allowMatureContentunset means the orchestrator decides after seeing which currency was charged: if the workflow settled with blue or green, it's treated as SFW; if it settled with yellow, mature content is allowed.
upgradeMode — when the output turns out mature
If the workflow was paid with blue or green Buzz (SFW) but the generated content is classified as mature, upgradeMode controls what happens:
"manual"— the mature output is withheld and the workflow waits on you. To release it, callUpdateWorkflow(PUT) orPatchWorkflow(PATCH) withallowMatureContent: true. The orchestrator refunds the blue/green Buzz and charges yellow. If your yellow balance is insufficient, the update returns400."automatic"— the orchestrator does that swap for you inline, charging the difference in yellow Buzz and delivering the mature output (or failing the workflow if yellow is insufficient).
Previewing cost
whatif=true returns a cost estimate, broken down per currency, without running the workflow.
The per-recipe path
POST https://orchestration.civitai.com/v2/consumer/recipes/chatCompletion?whatif=false
Authorization: Bearer <your-token>
Content-Type: application/json
{
"model": "openai/gpt-oss-120b",
"messages": [
{ "role": "user", "content": "Summarize this release note: ..." }
]
}Each /v2/consumer/recipes/{recipe} endpoint builds a single-step workflow for you, so:
- The request body is the step's
inputschema directly — no$type, nostepsarray. - The query parameters are
whatif,allowMatureContent,experimental,ephemeralandtier. There is nowaitorhideMatureContent, and no callbacks, tags, metadata orupgradeMode— use the generic path for those. - The call blocks until the workflow finishes (there is no
202), and the workflow is canceled if the connection drops first. Use the generic path for anything that may outlast your HTTP client's timeout. - The response is the step's output (e.g.
ChatCompletionOutput), not aWorkflow.
Updating and querying
After submitting, you can:
GetWorkflow— fetch by IDQueryWorkflows— list by tag, status, date rangeUpdateWorkflow/PatchWorkflow— amend metadata / tags, or raisedownloadPriorityAddWorkflowTag/RemoveWorkflowTag— tag maintenanceDeleteWorkflow— cancel / remove
UpdateWorkflow (PUT) returns 200 with the full workflow body, and accepts ?whatif=true to price a change without applying it.
Resource availability.status includes queued: a resource waiting in a download queue (it carries a queuePosition) reports queued, while unavailable means "eligible, but nothing is fetching it". Clients that exhaustively match on status must handle both.
UpdateWorkflowStep / PatchWorkflowStep update a step's metadata (the only field they accept) in any state; a step's input can't be changed.