Convilyn User Workflows API (1.0.0)

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.

Relationship to other surfaces

  • Developer Portal (/api/v1/developers/*, /api/v1/creator/*) — unchanged. Targets 3rd-party developers via SDK / API key, has sandbox verification flow.
  • User Workflows (this spec, /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.

Core invariants (contract-enforced)

  • I1: UserWorkflow has no requiredSlots / slots / triggerInputs field. Slot cost is eliminated by schema, not by UI toggle.
  • I2: Compiled DestinationSpec has requiredSlots: [].
  • I3: Compiled toolPalette never contains request_user_input — the agent cannot ask the user mid-execution.
  • I4: Every UserWorkflow has a sourceSpecId + sourceType. From-scratch uses sourceType: "blank", sourceSpecId: "blank".
  • I5: Public workflows cannot be hard-deleted, only archived (prevents dangling forkedFromId references for users who forked them).

Typical flow

  1. User browses curated Goal Lane templates OR the community gallery
  2. POST /user_workflows/fork → creates a UserWorkflow inheriting source's systemPrompt / toolPalette / outputSpecs
  3. User edits in Builder canvas (tool drag-drop + systemPrompt edit)
  4. PATCH /user_workflows/:id → saves changes, optionally flips visibility=public
  5. POST /jobs/goal { userWorkflowId, fileIds } → runs via shared Goal Lane agent
  6. Community: browse / fork / like other users' public workflows

Tier gating

  • Browse / fork / like — authenticated free users allowed
  • Create / edit / run / make-public — requires Pro tier

Error envelope

Matches existing Convilyn API (ErrorResponse schema).

User Workflows

CRUD for the authenticated user's own workflows

Import a workflow from a portable JSON file

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.

Server-side guarantees

  • Body cap: 256 KB. Larger requests reject with 413.
  • Tool palette is checked against the live MCP catalog (GET /mcp/tools/catalog); unknown ids return 422.
  • request_user_input / complete_workflow are forbidden by the shared UserWorkflow validator (I3).
  • Imported workflows are always created private. Publishing still requires a separate PATCH with the visibility transition.

Pairs with GET /user_workflows/{workflowId}/export.

Authorizations:
BearerAuth
Request Body schema: application/json
required
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 ]

Responses

Request samples

Content type
application/json
{
  • "schemaVersion": "string",
  • "name": "string",
  • "description": "string",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "tags": [
    ]
}

Response samples

Content type
application/json
{
  • "workflowId": "string",
  • "ownerId": "string",
  • "specId": "string",
  • "sourceSpecId": "string",
  • "sourceType": "curated",
  • "sourceVersion": "string",
  • "name": "string",
  • "description": "",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "specJson": { },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "stats": {
    },
  • "createdAt": "2019-08-24T14:15:22Z",
  • "updatedAt": "2019-08-24T14:15:22Z",
  • "itemVersion": 0
}

List my UserWorkflows

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.

Authorizations:
BearerAuth
query Parameters
visibility
string (Visibility)
Enum: "private" "public" "archived"

Filter by visibility

limit
integer [ 1 .. 100 ]
Default: 20
cursor
string

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "cursor": "string"
}

Create a blank UserWorkflow

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.

Authorizations:
BearerAuth
Request Body schema: application/json
required
name
required
string [ 1 .. 80 ] characters
description
string <= 500 characters

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string"
}

Response samples

Content type
application/json
{
  • "workflowId": "string",
  • "ownerId": "string",
  • "specId": "string",
  • "sourceSpecId": "string",
  • "sourceType": "curated",
  • "sourceVersion": "string",
  • "name": "string",
  • "description": "",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "specJson": { },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "stats": {
    },
  • "createdAt": "2019-08-24T14:15:22Z",
  • "updatedAt": "2019-08-24T14:15:22Z",
  • "itemVersion": 0
}

Get a UserWorkflow

Returns the full UserWorkflow. Owner sees any visibility; non-owner only sees workflows with visibility=public.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$

UserWorkflow ID (format uw_<uuid>)

Responses

Response samples

Content type
application/json
{
  • "workflowId": "string",
  • "ownerId": "string",
  • "specId": "string",
  • "sourceSpecId": "string",
  • "sourceType": "curated",
  • "sourceVersion": "string",
  • "name": "string",
  • "description": "",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "specJson": { },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "stats": {
    },
  • "createdAt": "2019-08-24T14:15:22Z",
  • "updatedAt": "2019-08-24T14:15:22Z",
  • "itemVersion": 0
}

Update a UserWorkflow

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.

Visibility transitions

  • 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).

Optimistic locking

Pass itemVersion to guard against concurrent edits. Server returns 409 if mismatched.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$

UserWorkflow ID (format uw_<uuid>)

Request Body schema: application/json
required
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.

  • private — only owner can see / run; hard-deletable.
  • public — in community gallery; forkable by any authenticated user; cannot be hard-deleted (I5).
  • archived — hidden from community browse but retained to keep prior fork lineage valid; hard-deletable.
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.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "itemVersion": 0
}

Response samples

Content type
application/json
{
  • "workflowId": "string",
  • "ownerId": "string",
  • "specId": "string",
  • "sourceSpecId": "string",
  • "sourceType": "curated",
  • "sourceVersion": "string",
  • "name": "string",
  • "description": "",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "specJson": { },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "stats": {
    },
  • "createdAt": "2019-08-24T14:15:22Z",
  • "updatedAt": "2019-08-24T14:15:22Z",
  • "itemVersion": 0
}

Delete a UserWorkflow

Delete an owned UserWorkflow.

  • private or archived → hard deleted (ok to remove).
  • publicrejected 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).
Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$

UserWorkflow ID (format uw_<uuid>)

Responses

Response samples

Content type
application/json
{
  • "code": "SOURCE_NOT_FOUND",
  • "message": "string",
  • "details": { }
}

Export a workflow as a portable JSON file

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.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$

Responses

Response samples

Content type
application/json
{
  • "schemaVersion": "1.0",
  • "name": "string",
  • "description": "string",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "tags": [
    ]
}

Fork

Create a UserWorkflow by forking a curated or community source

Fork a source into a new UserWorkflow

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).

Source types

  • goal_lane.* or developer_*.* — resolved via SpecRegistry
  • uw_* — resolved from UserWorkflowRepo
  • blank — produces an empty UserWorkflow

Tier

Fork itself is available to any authenticated user. Editing / running the forked workflow requires Pro.

Authorizations:
BearerAuth
Request Body schema: application/json
required
sourceSpecId
required
string

The spec_id to fork from, or "blank" for empty.

name
string <= 80 characters

Optional name for the new workflow. Defaults to "Copy of {source.name}".

Responses

Request samples

Content type
application/json
Example
{
  • "sourceSpecId": "goal_lane.action_items_extractor",
  • "name": "My weekly meeting tracker"
}

Response samples

Content type
application/json
{
  • "workflowId": "string",
  • "ownerId": "string",
  • "specId": "string",
  • "sourceSpecId": "string",
  • "sourceType": "curated",
  • "sourceVersion": "string",
  • "name": "string",
  • "description": "",
  • "systemPrompt": "string",
  • "toolPalette": [
    ],
  • "canvasLayout": {
    },
  • "specJson": { },
  • "visibility": "private",
  • "tags": [
    ],
  • "foundingIntent": "string",
  • "stats": {
    },
  • "createdAt": "2019-08-24T14:15:22Z",
  • "updatedAt": "2019-08-24T14:15:22Z",
  • "itemVersion": 0
}

Community

Browse and interact with public UserWorkflows

Browse public UserWorkflows

List community (public) workflows. Auth optional — anonymous browsing is allowed to lower discovery friction.

query Parameters
tag
string <= 24 characters

Filter by tag (exact match)

sort
string
Default: "recent"
Enum: "popular" "recent"
limit
integer [ 1 .. 50 ]
Default: 20
cursor
string

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "cursor": "string"
}

Toggle like on a public UserWorkflow

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.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$

Responses

Response samples

Content type
application/json
{
  • "liked": true,
  • "likeCount": 0
}

Post a comment on a public UserWorkflow

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.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$
Request Body schema: application/json
required
body
required
string [ 1 .. 2000 ] characters

Comment body, plain text. HTML / script / iframe / inline event handlers are rejected at the API layer (422).

Responses

Request samples

Content type
application/json
{
  • "body": "string"
}

Response samples

Content type
application/json
{
  • "commentId": "string",
  • "workflowId": "string",
  • "authorId": "string",
  • "body": "string",
  • "createdAt": "2019-08-24T14:15:22Z"
}

List comments on a UserWorkflow

Cursor-paginated list, newest first. Anonymous access is allowed for public workflows so the community discussion is discoverable without signing in.

path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$
query Parameters
limit
integer [ 1 .. 100 ]
Default: 50
cursor
string

Opaque cursor from a previous response's cursor field.

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "cursor": "string"
}

Delete one of your own comments

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.

Authorizations:
BearerAuth
path Parameters
workflowId
required
string^uw_[a-f0-9]{24}$
commentId
required
string^wc_[a-f0-9]{24}$

Responses