Download OpenAPI specification:
User-facing workflow builder API. Enables Pro users to fork curated Goal Lane workflows (or start from scratch), customize the system prompt and tool palette via a drag-and-drop canvas, persist the result, and share with the community.
/api/v1/developers/*, /api/v1/creator/*) — unchanged.
Targets 3rd-party developers via SDK / API key, has sandbox verification flow./api/v1/user_workflows/*) — NEW.
Targets Pro end-users via JWT, no sandbox (direct persist), includes community.Both surfaces output DestinationSpec JSON and register into the shared
SpecRegistry, so the same Goal Lane agent runtime serves both.
requiredSlots / slots / triggerInputs field.
Slot cost is eliminated by schema, not by UI toggle.requiredSlots: [].toolPalette never contains request_user_input — the agent
cannot ask the user mid-execution.sourceSpecId + sourceType. From-scratch
uses sourceType: "blank", sourceSpecId: "blank".forkedFromId references for users who forked them).Atomic alternative to POST /user_workflows (createBlank) followed
by PATCH. Accepts a sanitised JSON shape — the server discards
any ownerId, workflowId, stats, itemVersion, specJson, or
timestamp fields and assigns its own.
GET /mcp/tools/catalog); unknown ids return 422.request_user_input / complete_workflow are forbidden by the
shared UserWorkflow validator (I3).private. Publishing still
requires a separate PATCH with the visibility transition.Pairs with GET /user_workflows/{workflowId}/export.
| schemaVersion | string Optional discriminator from the export file. |
| name required | string [ 1 .. 80 ] characters |
| description | string <= 500 characters |
| systemPrompt | string <= 8000 characters |
Array of objects (ToolPaletteItem) <= 20 items | |
object (CanvasLayout) Optional Builder-only UI state. Ignored by the compiler and the agent. Safe to evolve independently of the DestinationSpec contract. | |
| tags | Array of strings <= 8 items [ items [ 1 .. 24 ] characters ] |
{- "schemaVersion": "string",
- "name": "string",
- "description": "string",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "tags": [
- "string"
]
}{- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "sourceSpecId": "string",
- "sourceType": "curated",
- "sourceVersion": "string",
- "name": "string",
- "description": "",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "specJson": { },
- "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "itemVersion": 0
}List the authenticated user's own workflows. Paginated, newest first.
Returns UserWorkflowSummary (short form, excludes full systemPrompt
and specJson to keep payload small). Use GET /user_workflows/:id for
the full record.
| visibility | string (Visibility) Enum: "private" "public" "archived" Filter by visibility |
| limit | integer [ 1 .. 100 ] Default: 20 |
| cursor | string |
{- "items": [
- {
- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "name": "string",
- "descriptionPreview": "string",
- "visibility": "private",
- "tags": [
- "string"
], - "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "sourceType": "curated",
- "sourceSpecId": "string",
- "updatedAt": "2019-08-24T14:15:22Z"
}
], - "cursor": "string"
}Create an empty UserWorkflow (from-scratch path). Requires Pro tier.
The workflow starts with an empty systemPrompt and empty toolPalette.
Must be populated via PATCH before it can be run.
For most users, prefer POST /user_workflows/fork with an existing source.
| name required | string [ 1 .. 80 ] characters |
| description | string <= 500 characters |
{- "name": "string",
- "description": "string"
}{- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "sourceSpecId": "string",
- "sourceType": "curated",
- "sourceVersion": "string",
- "name": "string",
- "description": "",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "specJson": { },
- "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "itemVersion": 0
}Returns the full UserWorkflow. Owner sees any visibility; non-owner only
sees workflows with visibility=public.
| workflowId required | string^uw_[a-f0-9]{24}$ UserWorkflow ID (format |
{- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "sourceSpecId": "string",
- "sourceType": "curated",
- "sourceVersion": "string",
- "name": "string",
- "description": "",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "specJson": { },
- "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "itemVersion": 0
}Partial update of an owned UserWorkflow. Only the owner can patch. Requires Pro tier.
Fields outputSpecs and agentConfig are read-only in MVP (inherited
from source at fork time); any value in the request is silently ignored.
v1.1 will open these for editing.
private → public triggers a content safety check on systemPrompt
(profanity / PII regex). Returns 422 CONTENT_POLICY_VIOLATION if it
fails.public → archived is allowed; public → private is not (forkers
may still reference it).Pass itemVersion to guard against concurrent edits. Server returns 409
if mismatched.
| workflowId required | string^uw_[a-f0-9]{24}$ UserWorkflow ID (format |
| name | string [ 1 .. 80 ] characters |
| description | string <= 500 characters |
| systemPrompt | string <= 8000 characters |
Array of objects (ToolPaletteItem) <= 20 items | |
object (CanvasLayout) Optional Builder-only UI state. Ignored by the compiler and the agent. Safe to evolve independently of the DestinationSpec contract. | |
| visibility | string (Visibility) Enum: "private" "public" "archived" Lifecycle visibility state.
|
| tags | Array of strings <= 8 items [ items [ 1 .. 24 ] characters ] |
| foundingIntent | string or null <= 1000 characters Optional — pass to update the owner's free-form "why I built this" prose. Omit to leave the existing value unchanged. (Phase 7a) |
| itemVersion | integer >= 0 Required for optimistic locking. |
{- "name": "string",
- "description": "string",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "itemVersion": 0
}{- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "sourceSpecId": "string",
- "sourceType": "curated",
- "sourceVersion": "string",
- "name": "string",
- "description": "",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "specJson": { },
- "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "itemVersion": 0
}Delete an owned UserWorkflow.
private or archived → hard deleted (ok to remove).public → rejected with 409. Caller must PATCH visibility to
archived first, then retry DELETE. This protects users who forked
your workflow (their forkedFromId still resolves to an archived row).| workflowId required | string^uw_[a-f0-9]{24}$ UserWorkflow ID (format |
{- "code": "SOURCE_NOT_FOUND",
- "message": "string",
- "details": { }
}Returns a download (Content-Disposition: attachment) containing
only the portable subset of the workflow:
name, description, systemPrompt, toolPalette, canvasLayout,
tags, plus a schemaVersion discriminator.
Owner-only. The body intentionally omits ownerId, workflowId,
specId, sourceSpecId, sourceVersion, stats, itemVersion,
specJson, createdAt, and updatedAt. Pair with
POST /user_workflows/import.
| workflowId required | string^uw_[a-f0-9]{24}$ |
{- "schemaVersion": "1.0",
- "name": "string",
- "description": "string",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "tags": [
- "string"
]
}Create a UserWorkflow by forking either a curated spec (e.g.
goal_lane.action_items_extractor) or an existing public/own UserWorkflow.
The new UserWorkflow inherits the source's systemPrompt, toolPalette,
outputSpecs, and agentConfig. Its visibility defaults to private
and stats counters start at zero. The source's stats.forkCount is
atomically incremented (only for UserWorkflow sources; curated sources
have no counters).
goal_lane.* or developer_*.* — resolved via SpecRegistryuw_* — resolved from UserWorkflowRepoblank — produces an empty UserWorkflowFork itself is available to any authenticated user. Editing / running the forked workflow requires Pro.
| sourceSpecId required | string The spec_id to fork from, or |
| name | string <= 80 characters Optional name for the new workflow. Defaults to "Copy of {source.name}". |
{- "sourceSpecId": "goal_lane.action_items_extractor",
- "name": "My weekly meeting tracker"
}{- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "sourceSpecId": "string",
- "sourceType": "curated",
- "sourceVersion": "string",
- "name": "string",
- "description": "",
- "systemPrompt": "string",
- "toolPalette": [
- {
- "toolName": "doc-parser-mcp:extract_text",
- "position": {
- "x": 0.1,
- "y": 0.1
}, - "note": "string"
}
], - "canvasLayout": {
- "edges": [
- {
- "from": "string",
- "to": "string"
}
], - "viewport": {
- "zoom": 0,
- "pan": {
- "x": 0.1,
- "y": 0.1
}
}
}, - "specJson": { },
- "visibility": "private",
- "tags": [
- "string"
], - "foundingIntent": "string",
- "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "createdAt": "2019-08-24T14:15:22Z",
- "updatedAt": "2019-08-24T14:15:22Z",
- "itemVersion": 0
}List community (public) workflows. Auth optional — anonymous browsing is allowed to lower discovery friction.
| tag | string <= 24 characters Filter by tag (exact match) |
| sort | string Default: "recent" Enum: "popular" "recent" |
| limit | integer [ 1 .. 50 ] Default: 20 |
| cursor | string |
{- "items": [
- {
- "workflowId": "string",
- "ownerId": "string",
- "specId": "string",
- "name": "string",
- "descriptionPreview": "string",
- "visibility": "private",
- "tags": [
- "string"
], - "stats": {
- "runCount": 0,
- "forkCount": 0,
- "likeCount": 0
}, - "sourceType": "curated",
- "sourceSpecId": "string",
- "updatedAt": "2019-08-24T14:15:22Z",
- "ownerDisplayName": "string",
- "sourceName": "string"
}
], - "cursor": "string"
}Idempotent toggle — calling again unlikes. Only public workflows are
likeable. Server maintains a TemplateLike row per (user, workflow)
for exactness and updates the workflow's stats.likeCount atomically.
| workflowId required | string^uw_[a-f0-9]{24}$ |
{- "liked": true,
- "likeCount": 0
}Authenticated users can comment on any PUBLIC workflow. The body is stored as plain text; HTML / script / iframe payloads are rejected at the API layer (defence-in-depth) — clients are still expected to render the body verbatim, never as HTML.
| workflowId required | string^uw_[a-f0-9]{24}$ |
| body required | string [ 1 .. 2000 ] characters Comment body, plain text. HTML / script / iframe / inline event handlers are rejected at the API layer (422). |
{- "body": "string"
}{- "commentId": "string",
- "workflowId": "string",
- "authorId": "string",
- "body": "string",
- "createdAt": "2019-08-24T14:15:22Z"
}Cursor-paginated list, newest first. Anonymous access is allowed for public workflows so the community discussion is discoverable without signing in.
| workflowId required | string^uw_[a-f0-9]{24}$ |
| limit | integer [ 1 .. 100 ] Default: 50 |
| cursor | string Opaque cursor from a previous response's |
{- "items": [
- {
- "commentId": "string",
- "workflowId": "string",
- "authorId": "string",
- "body": "string",
- "createdAt": "2019-08-24T14:15:22Z"
}
], - "cursor": "string"
}Only the comment author can delete. Workflow owners do NOT have moderation rights in V1 — moderation flow can layer on top later without schema change.
| workflowId required | string^uw_[a-f0-9]{24}$ |
| commentId required | string^wc_[a-f0-9]{24}$ |