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",
- "treasureId": "string"
}
], - "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
}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"
]
}Runs the SAME validator chain the register flow uses, returning
structured errors so the chat agent can gate stage_draft →
register on the validator's verdict.
| name required | string [ 1 .. 80 ] characters |
| description | string <= 500 characters |
| systemPrompt | string <= 8000 characters |
| toolPalette | Array of strings <= 20 items |
{- "name": "string",
- "description": "string",
- "systemPrompt": "string",
- "toolPalette": [
- "string"
]
}{- "success": true,
- "errors": [
- "string"
], - "failureType": "string"
}Owner-only. Returns up to limit most-recent runs of this workflow,
newest first. MVP scope: scans the caller's recent jobs and filters
by the workflow's compiled spec_id; a dedicated spec_id GSI is a
later optimisation.
| workflowId required | string^uw_[a-f0-9]{24}$ |
| limit | integer [ 1 .. 50 ] Default: 5 |
{- "items": [
- {
- "jobSpecId": "string",
- "status": "string",
- "startedAt": "2019-08-24T14:15:22Z",
- "completedAt": "2019-08-24T14:15:22Z",
- "progress": 100,
- "errorCode": "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",
- "treasureId": "string",
- "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}$ |
Returns an upper-bound micro-U estimate for one run of the currently staged tool palette. Read-only — no DDB writes, no tier check. Used by the chat agent / Run CTA to surface cost impact BEFORE the user triggers a run.
Estimate model:
estimated = (sum(toolCost) + baseLlmCostPerIter) × maxIterations
Unknown tool ids contribute zero to the estimate — the validate endpoint is the registration gate, so the cost path stays usable even when the catalogue lookup is degraded.
| toolNames required | Array of strings <= 20 items [ items [ 1 .. 128 ] characters ] Fully-qualified tool ids the agent has staged on the canvas,
in the same |
| maxIterations | integer or null [ 1 .. 200 ] Iteration cap from the draft spec. Defaults to the compiler's DEFAULT_MAX_ITERATIONS (20) when omitted. |
{- "toolNames": [
- "string"
], - "maxIterations": 1
}{- "estimatedMicroU": 0,
- "estimatedUsd": 0.1,
- "maxIterations": 1,
- "llmCostPerIterMicroU": 0,
- "tools": [
- {
- "toolName": "string",
- "perInvocationMicroU": 0
}
], - "quotaCheck": {
- "state": "ok",
- "tier": "free",
- "estimatedMicroU": 0,
- "thresholdMicroU": 0,
- "upgradeUrl": "string"
}
}