Skip to content
Select themeSelect language

Provision a workspace from a template

A workflow template is a ready-made workflow you can materialize into a project instead of drawing the graph yourself. Two shipped templates cover the common intake shapes:

Slug What it does How it fires
mail_intake Picks up incoming mail from a mailbox and starts a task per message IMAP trigger on a mailbox resource
scan_intake Sweeps a document library for new files and starts a task per document Schedule (daily by default)

The Management API can create these for you, so connecting a mailbox is a single request rather than a manual assembly in the builder.

The workflow template gallery — one tile per shipped template with its trigger kind, including Mail intake (imap) and Scan intake (schedule).The workflow template gallery — one tile per shipped template with its trigger kind, including Mail intake (imap) and Scan intake (schedule).
  1. Declare the mailbox as a resource.

    The resource’s name is the identity you refer to later — there is no separate key field, and the reference below matches the name character for character. Pick a name you are happy to type again. The password is write-only: it is never returned by a read of the workspace state.

    {
    "resources": [
    {
    "name": "workspace-mailbox",
    "kind": "imap",
    "config": {
    "host": "mail.example.com",
    "port": 993,
    "username": "intake@example.com"
    },
    "secret": "the-mailbox-password"
    }
    ]
    }
  2. Materialize the workflow from the template.

    The IMAP trigger binds the mailbox by its id, so write the reference form ${{ resources.<name>.id }} — it is resolved against the resource you declared in step 1, in this same request, so you never paste a UUID.

    {
    "workflow_templates": [
    {
    "key": "mail-intake",
    "project_key": "my-project",
    "template": "mail_intake",
    "name": "Mailbox Intake",
    "config": {
    "mailbox_resource_id": "${{ resources.workspace-mailbox.id }}"
    }
    }
    ]
    }

    Every other blank in the template has a working default, so this one line is enough to get a running mailbox intake:

    config key Default What it fills
    mailbox_resource_id (none) The mailbox to poll. Omit it and the workflow is materialized without a trigger, for you to attach one later.
    mailbox_folder INBOX The folder the trigger polls.
    agent_type claude The agent that triages and handles each message.
    mailbox_label the connected mailbox How the prompt refers to this mailbox.
    intake_purpose A generic sentence What this mailbox is for — the triage step’s yardstick.
    approval_note A generic sentence Extra guidance shown to the human approver.
    handling_instructions House rules about not disclosing credentials How the handler should carry out an approved action.
  3. Send both blocks in one request.

    Terminal window
    curl -X PUT \
    -H "Authorization: Bearer $SUPACLOUD_MANAGEMENT_TOKEN" \
    -H "Content-Type: application/json" \
    --data @workspace-state.json \
    https://app.example.com/api/management/v1/workspaces/my-workspace/state

    The blocks apply in a fixed order — resources, then projects, then workflow templates, then triggers and schedules — so everything a later block refers to already exists.

The scan template works against a document library instead of a mailbox, and it binds that library by plain name — not by id. Its two program steps reach the library through a binding that is resolved by resource name, so write the name itself, exactly as declared:

{
"resources": [
{
"name": "document-library",
"kind": "seafile_webdav",
"config": {
"base_url": "https://seafile.example.com/seafdav",
"user": "scanner@example.com",
"library_path": "/Documents",
"repo_name": "Documents"
},
"secret": "the-seafile-password"
}
],
"workflow_templates": [
{
"key": "scan-intake",
"project_key": "my-project",
"template": "scan_intake",
"config": {
"library_resource": "document-library",
"scan_folder": "/Inbox",
"archive_folder": "/Archive"
}
}
]
}
config key Default What it fills
library_resource scans The name of the seafile_webdav resource to sweep. A name no resource has fails the request.
scan_folder /Inbox The drop folder that is swept.
archive_folder /Archive Where a confirmed batch is moved to.
file_extensions .pdf,.jpg,.jpeg,.png,.tif,.tiff Which files count as documents.
lookback_minutes 1440 How far back a sweep looks for new files.
review_note A generic sentence Extra guidance shown to the human confirming a batch.

The library resource carries two location fields, and the scan template needs both kinds of information:

config field Required What reads it
base_url yes The WebDAV/Seafile host. It is also the only host the two program steps may reach.
user yes The Seafile account the steps authenticate as.
library_path yes The WebDAV path of the library, required by the seafile_webdav resource kind.
repo_name one of the two The library’s display name. The steps look the library up by it.
repo_id one of the two The library’s id, if you already know it. Set it and repo_name is not consulted.
web_base_url no The Seafile web host, when it differs from base_url.

Give either repo_name or repo_id. With neither, the resource is still accepted — the two fields are optional to the resource kind — but the first sweep fails with Seafile library is not resolvable by name: ''.

Because a document library has no push notification, this template runs on a schedule rather than a trigger. Add its cadence with a workflow_schedules entry naming the materialized workflow — Scan intake unless you set a name override on the template entry:

{
"workflow_schedules": [
{
"key": "scan-sweep",
"project_key": "my-project",
"workflow": "Scan intake",
"cadence": "daily",
"timezone": "Europe/Berlin",
"next_run_at": "2026-09-01T06:00:00Z"
}
]
}

Applying the same document again is safe and does nothing:

  • A template whose workflow already exists reports changed: false. The apply never overwrites your edits — once the workflow is materialized, the graph belongs to you, so you can freely adjust it in the builder.
  • Removing an entry from the document does not delete the workflow. Every list in the workspace state is additive; deletion is always an explicit action.
  • Renaming the workflow is safe. Reconciliation uses the key you chose, not the display name.

A config value fills one blank in the shipped template — a folder, a label, a sentence of guidance. The template is read as a document first, and your value is then placed into the single blank it belongs to, so it stays one piece of text: it cannot add a step, rename a field, or reach a second blank, whatever it contains. A config key that names no blank in the template fills nothing.

Two things a value still cannot do, because they are about what reads it afterwards rather than about the document. Both are checked before anything is created, and a value that fails one fails the request with 400, naming the key:

  • The scan template’s program. Its two steps run a small program against your library, with the library’s credential in reach, and a few blanks sit inside that program’s text (scan_folder, archive_folder, file_extensions, lookback_minutes). A value there may not contain " or \, which would end the quoted text it is placed into.
  • A second template marker. No value may contain ${{ … }}. Prompts and program text are filled in again while the workflow runs, so a marker smuggled through now would be expanded later against live data. The single exception is the ${{ resources.<name>.id }} reference form, which is resolved into a UUID before the value reaches the template at all.

Two more rules round it off: keep each value on one line (a line break is refused rather than reinterpreted — put longer guidance in the builder afterwards), and keep it under 8192 characters.

New projects do not receive these workflows. Both templates are opt-in — through this block or the picker — so adding them changes nothing for projects that already exist.