Unpublish a workflow
POST/
Takes a workflow offline: its triggers stop, and its draft and versions stay.
Needs an API token with the Publish permission for workflows (workflow:publish).
Parameters
Path
idRequired · UUIDThe workflow’s ID.
Body
Optional.
expectedRevOptional · integerThe
definitionRevyou read. If the draft changed since, nothing happens and you get 409. Left out, 0 or less: no check.
What stops, and what stays
Schedules skip it, and its webhook address answers 404. Runs already going are not cancelled.
The webhook address stays the same, so publishing again brings it back. A self-registering trigger is signed off from its service. A trigger that checks a service for new items starts from now when you publish again, not from where it stopped.
Its runs waiting in line stay. Cancel them if you don’t want them.
Responses
- 200OK
Paused. A paused workflow answers 200 as it is, and a draft stays a draft.
idisn’t a UUID, orexpectedRevisn’t a whole number.- 403
FORBIDDENThe token lacks the Publish permission for workflows.
Only Keel’s own publish card sends this: a write no person clicked. An API call never gets it.
- 404
NOT_FOUNDNo workflow with this ID in the token’s workspace.
- 409
CONFLICTexpectedRevis out of date: someone saved since. Nothing changed. Read the workflow again. - 409
CONFLICTAnother write to this workflow took too long. Try again.
The workflow is still live. Try again.
Any call can also answer: 401 UNAUTHORIZED · 401 TOKEN_ENDED · 403 TOKEN_SURFACE_OFF · 403 FEATURE_OFF · 403 EMBED_NOT_ALLOWED · 403 EMBED_NOT_AVAILABLE · 403 ACCOUNT_SUSPENDED · 413 PAYLOAD_TOO_LARGE · 415 INVALID_CONTENT_TYPE · 429 RATE_LIMITED · 503 BUSY · 503 PAUSED · 503 SERVICE_UNAVAILABLE. See Errors.
Request
GORUNNER="https://api.gorunner.io"
GORUNNER_TOKEN="grt_…" # needs Publish for workflows
WORKFLOW_ID="your-workflow-id"
URL="$GORUNNER/api/workflows/$WORKFLOW_ID/unpublish"
curl -X POST "$URL" \
-H "Authorization: Bearer $GORUNNER_TOKEN"const GORUNNER = "https://api.gorunner.io";
const TOKEN = process.env.GORUNNER_TOKEN;
const WORKFLOW_ID = process.env.WORKFLOW_ID;
const res = await fetch(
`${GORUNNER}/api/workflows/${WORKFLOW_ID}/` +
`unpublish`,
{
method: "POST",
headers: { Authorization: `Bearer ${TOKEN}` },
},
);
const { data } = await res.json();import os, requests
GORUNNER = "https://api.gorunner.io"
TOKEN = os.environ["GORUNNER_TOKEN"]
WORKFLOW_ID = os.environ["WORKFLOW_ID"]
res = requests.post(
f"{GORUNNER}/api/workflows/{WORKFLOW_ID}/"
f"unpublish",
headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]Response · 200 OK, shortened
{
"data": {
"id": "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
"name": "Order intake",
"status": "paused",
"triggerType": "webhook",
"latestVersionId": "f20f671a-2c8e-4b9d-a7f1-6e3b0d5c9a12",
"definitionRev": 7,
"updatedAt": "2026-10-24T16:40:00Z"
}
}Every field
Body
expectedRevOptional · integerThe
definitionRevof the draft the caller holds. Makes the write conditional: a draft that moved since gives 409 and nothing is written. Omit — or send 0 or less, which is ignored — for an unconditional write.
Response · 200 OK
dataobjectA workflow.
definitionis the DRAFT — what the editor saves into. Production executes the snapshot named bylatestVersionIdinstead, which is whyhasUnpublishedChangesmatters.idUUIDnamestringdescriptionstringdefinitionobjectThe workflow definition. It is a TREE, not a list of steps: the trigger holds
nextAction, each action holds the next one, and branches/loops/error paths nest their own sub-chains. A flatactionsarray is not a definition and would execute nothing.A workflow definition: its fields are in Workflow definition.
statusstringdraft= never published.active= live, triggers registered, public webhook reachable.paused= was live, toggled off.One of
draft,active,paused.triggerTypestringDerived from the definition’s trigger on every write. Only
webhookworkflows have awebhookToken.One of
manual,cron,webhook,error,run_finished,poll.cronExpressionstring or nullwebhookTokenstring or nullThe workflow’s public production door.
POST /api/webhooks/{webhookToken}is UNAUTHENTICATED — the unguessable URL is the credential. Minted by publish for a webhook workflow, revoked and replaced byPOST /api/workflows/{id}/webhook/rotate. Present here only for a credential holdingworkflow:run; redacted below that, and never present in the workflow LIST.latestVersionIdUUID or nullThe published snapshot production runs. Null until first publish.
definitionRevintegerOptimistic-lock revision, bumped on every save. Pass it back as
expectedRevto make a write conditional. Present on the single-workflow read and on write responses; absent (0) in lists.hasUnpublishedChangesbooleanTrue when the draft has moved ahead of what is live. Computed in SQL, so it is exact — undoing an edit back to the published bytes reads false again.
folderIdUUID or nulltagsarray of stringstestPayloadsobject or nullSaved test fixtures. Stored outside the definition, so publish/restore never resets them.
pinnedDataobject or nullFrozen step outputs replayed instead of executing, TEST runs only. Stored outside the definition.
workspaceIdUUIDorgIdUUIDcreatedByUUID or nullcreatedAttimeupdatedAttime