Task integration shapes
Agent contract
Start with the machine-readable JSON reference.
POST /api/v1/tasks/createOrUpdateTask with Content-Type: application/json and x-api-key: <project key>. The key supplies project context; no project header is needed.
Create: omit id; supply name and steps. Update: GET the task first and retain revision, step IDs and instruction IDs. Saving does not run a task.
Check a proposed request with POST /api/v1/tasks/validate using the same body and authentication. Discover models and permitted Run as emails through GET /api/v1/tasks/authoring-options. Model discovery does not guarantee provider credentials are configured.
Minimal working example
{
"name": "Hello task",
"steps": [
{
"type": "code",
"name": "Prepare result",
"fields": {
"code": "return { message: \"Hello\" };",
"output": "result",
"format": "json"
}
}
]
}
Minimal AI agent example
Replace the model with an available language model from authoring-options.
{
"name": "Hello AI",
"steps": [
{
"type": "ai_agent",
"name": "Say hello",
"fields": {
"prompts": [
{
"prompt": "Say hello in one short sentence.",
"output": "greeting",
"model": "gpt-5.5",
"response": "string"
}
]
}
}
]
}Discover models and Run as users
GET /api/v1/tasks/authoring-options uses your project API key and takes no query parameters.
Filter models client-side by type: 1 for language prompts, 2 for media workflows, 3 for transcription. Use model verbatim. run_as contains eligible project-member emails: your identity, or other eligible members if you are an organization-admin. Values and timezone in this example are illustrative; use your server response.
| Field | Type | Required | Details |
|---|---|---|---|
models | array | Yes | Items: 0–10000 |
models[].model | string | Yes | Maximum length: 200 Pattern: \S |
models[].type | integer | Yes | Minimum: 1 Maximum: 3 |
model_types | object | Yes | |
model_types.1 | string | Yes | Values: language |
model_types.2 | string | Yes | Values: media |
model_types.3 | string | Yes | Values: speech_to_text |
run_as | array | Yes | Items: 0–10000 |
api_server_timezone | string | Yes | Maximum length: 20000 |
schedule_timezone | string | Yes | Maximum length: 20000 |
notes | array | Yes | Items: 0–100 |
{
"models": [
{
"model": "gpt-5.5",
"type": 1
},
{
"model": "whisper-1",
"type": 3
}
],
"model_types": {
"1": "language",
"2": "media",
"3": "speech_to_text"
},
"run_as": [
"user@example.com"
],
"api_server_timezone": "Europe/London",
"schedule_timezone": "Scheduler host local timezone; the scheduler and API hosts must use the same timezone.",
"notes": [
"Models are organization-approved and enabled for this project; credentials and provider availability are checked at execution."
]
}
For a paginated model list with optional type filtering, use GET /api/v1/models. Example: /api/v1/models?type=1 lists language models available to your project.
AI response types
| response | Meaning |
|---|---|
string | Text response, commonly Markdown. |
json | Parsed JSON object or array. Describe the required structure in the prompt. |
foreach | Existing per-item instruction processing mode; not a substitute for a for_each step. Retain for configured legacy instructions. |
code | Requests executable code as the answer. This response setting is not a code execution step. |
media | Media response mode; requires a compatible model and configured media workflow. |
task | Requests a JSON array of task objects, each with a description; not a createOrUpdateTask payload. |
list | Legacy list mode used by export/dynamic-function workflows. Prefer json for a new AI-generated array. |
Create and update schemas
task_schema is the create/update oneOf contract. schedule_schema is authoritative; schedule_types is a readable index of the same variants. Calendar validity and interval stop_time > start_time are checked by POST /api/v1/tasks/validate; schema alone cannot compare these values.
Creates require name and at least one step, with no task id or revision. Updates require id and at least one editable field; omitted fields remain unchanged. An inactive task may be updated with an empty steps list.
Successful responses
Create: 201
{
"created": true,
"task": {
"id": "0123456789abcdef01234567",
"revision": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"name": "Hello task",
"steps": [
{
"id": "0123456789abcdef01234568",
"type": "code",
"name": "Prepare result",
"fields": {
"code": "return { message: \"Hello\" };",
"output": "result",
"format": "json"
},
"description": ""
}
],
"active": false,
"schedule": {
"type": "manual"
},
"run_as": "user@example.com",
"notification": "errors",
"notification_emails": [],
"log_reference": ""
}
}Update: 200
{
"created": false,
"task": {
"id": "0123456789abcdef01234567",
"revision": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"name": "Hello task updated",
"steps": [
{
"id": "0123456789abcdef01234568",
"type": "code",
"name": "Prepare result",
"fields": {
"code": "return { message: \"Hello\" };",
"output": "result",
"format": "json"
},
"description": ""
}
],
"active": false,
"schedule": {
"type": "manual"
},
"run_as": "user@example.com",
"notification": "errors",
"notification_emails": [],
"log_reference": ""
}
}Validate: 200
{
"valid": true,
"issues": [],
"warnings": [
"Validation does not execute steps or verify external services."
]
}
Common mistakes
- Use unique step names.
- Keep newly authored parent/branch subtrees contiguous.
- Supplying steps replaces the entire list; omit it for settings-only updates.
- Queued or running tasks cannot be edited.
- Use an exact model from authoring-options; credentials must also be configured.
- Output names do not include {{braces}}.
- Retain IDs on renames, and update child parent names.
- Do not delete unsupported steps to silence validation errors. Return them unchanged with their IDs.
Choosing an AI type
Use ai_agent for new agent tasks. ai_answer defaults to direct answer context. These are not interchangeable aliases despite sharing the same fields.
Editing existing tasks
Returned IDs preserve private settings across renames. Unchanged unsupported steps can be returned with their IDs. Existing branch layouts are preserved for content edits; changing the layout applies the rules below. Include the returned revision to detect stale edits (409). Do not drop unsupported steps to make a request pass validation.
Use this guide to create task steps through POST /api/v1/tasks/createOrUpdateTask. The integration type is supplied in type; every step has a fields object. The examples cover all 11 types currently supported by this API. Other UI integrations are not yet supported.
AI agents can read the same reference as JSON, including field schemas and examples. These pages contain no project data and need no login. Actual task requests require authentication.
Authenticate and save
x-api-key: <project API key>. The key supplies project context; no project header is needed.
Supply id to update an existing task; omit it to create. New tasks require a name and at least one step and default to inactive. Saving does not run a task. run_as is a project member’s email address; omit it to use your own identity on creation. Assigning another user requires organization-admin permission. Replace example emails and model/instruction references with your own values.
On update, omitted fields are preserved. For existing step content, prefer step_updates: [{id, fields: {code: "..."}}] with the task ID and latest revision. Supply only changed fields or description; fields merge by top-level name, while nested objects and arrays replace their entire field. The server validates the merged draft. Step updates cannot rename, add, remove, reorder or change types or branches, and cannot accompany steps. Supplying steps replaces the complete list; supplying schedule replaces the schedule. Unknown fields are rejected. Use GET /api/v1/tasks/{id} to read a task first. Queued or running tasks cannot be edited.
Common step fields
AI steps put their prompt list in fields.prompts. Every prompt contains prompt, output, model and response.
| Field | Type | Required | Details |
|---|---|---|---|
type | string | Yes | One of the types below. |
name | string | Yes | Unique within the task; case-sensitive after trimming. |
description | string | No | Optional explanation of what this step does. |
fields | object | Yes | Configuration for this type; see the field tables below. |
parent | string | No | Name of an earlier loop or if step. Keep each child subtree contiguous. |
branch | string | No | Required only for an if child. Each if needs one child for each branch. Values: true, false |
Integration types
http_request
Make an HTTP request. Text fields support existing {{tags}}.
Prefer an object for headers. For JSON requests use format: "json" and an object or array body. JSON-encoded strings remain accepted. output names the result used by later {{tags}}.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
method | string | Yes | Values: GET, POST, PUT, DELETE |
url | string | Yes | Maximum length: 4000 Pattern: \S |
headers | string | object | No | Header object or JSON-encoded text; supports {{tags}}. |
body | string | object | array | No | JSON object/array or text. |
format | string | No | Values: json, text, x-www-form-urlencoded, none Default: "json" |
output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
Step example
{
"type": "http_request",
"name": "Fetch orders",
"description": "",
"fields": {
"method": "GET",
"url": "https://example.com/orders",
"headers": {
"Accept": "application/json"
},
"output": "orders"
}
}code
Execute a JavaScript server function in the secure runtime.
code is the JavaScript function body. Return the native result to store it under output. Input tags are JavaScript literals, including escaped quotes for strings: use const po = {{purchase_order_number}}; const orders = {{orders}}; Do not surround tags with quotes or backticks, strip quotes, or JSON.parse values just to undo substitution. Assign tags to variables before building strings. Output options are String (format: "none"), JSON (format: "json"), and x-www-form-urlencoded (format: "x-www-form-urlencoded"). For a constant use return "SWM948681"; with format: "none". Use format: "json" for objects/arrays. format controls output processing, not input tag quoting.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
code | string | Yes | JavaScript function body; return the native result. Input {{tags}} are substituted as JavaScript literals: strings already include escaped quotes, arrays/objects retain their structure. Use const po = {{purchase_order_number}}; const orders = {{orders}}; Never wrap input tags in quotes or backticks, or JSON.parse them just to undo substitution. For interpolation, assign the tag to a variable first and then build the string. Do not JSON.stringify the return value just to pass it to another step. Maximum length: 200000 Pattern: \S |
output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
format | string | No | Select explicitly from the returned value, not the input. String (none): text, IDs, purchase order numbers, and ID-or-null lookups such as return matchingOrder?._id ?? null;. JSON (json): native objects, arrays, numbers or booleans. x-www-form-urlencoded: deliberately URL-encoded form text needed downstream. A null fallback or JSON input does not make a string result JSON. Review every return path and its downstream use. Output processing only; does not change input tag quoting. Values: none, json, x-www-form-urlencoded Default: "json" |
Step example
{
"type": "code",
"name": "Prepare orders",
"description": "",
"fields": {
"code": "return [{ number: \"PO1001\" }];",
"output": "orders",
"format": "json"
}
}for_each
Repeat child steps over a list. Children refer to this earlier step by name in parent. The current runner does not support a loop or if as a loop child.
This step needs at least one following child with parent set to this step’s name. Loop children must be contiguous. Nested loops and if statements inside loops are not supported by the current runner.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
list | string | Yes | Maximum length: 1000 Pattern: \S |
item | string | No | Output tag name without {{braces}}. Default: "item" Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
index | string | No | Output tag name without {{braces}}. Default: "index" Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
max_iterations | integer | No | Default: 1000 Minimum: 1 Maximum: 10000 |
continue_on_error | boolean | No | Default: false |
output | string | No | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
Step example
{
"type": "for_each",
"name": "Each order",
"description": "",
"fields": {
"list": "orders",
"item": "order",
"index": "orderIndex",
"max_iterations": 1000,
"continue_on_error": false,
"output": "orderResults"
}
}if_statement
Run condition code returning a boolean. Requires one true and one false child, each referring to this step by name in parent and specifying branch. Keep each branch subtree together in list order.
This step needs exactly one true child and one false child. Each child uses parent and branch ("true" or "false" as strings). A branch can be a loop or another if. Keep each branch subtree together.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
code | string | Yes | Maximum length: 200000 Pattern: \S |
output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
Step example
{
"type": "if_statement",
"name": "Has orders",
"description": "",
"fields": {
"code": "return {{orders}}.length > 0;",
"output": "hasOrders"
}
}log_response
Append a response to the task log. Supports {{tags}}.
Text can reference earlier results using {{outputName}}.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
subject | string | No | Maximum length: 500 |
body | string | Yes | Maximum length: 20000 Pattern: \S |
Step example
{
"type": "log_response",
"name": "Record result",
"description": "",
"fields": {
"subject": "Order results",
"body": "{{matchedProducts}}"
}
}send_email
Send using the Run as user’s connected mailbox. Supports {{tags}} in recipient, subject and body.
Uses the run_as user’s connected mailbox. Mail permissions must already be configured for that user.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
to | string | Yes | Maximum length: 2000 Pattern: \S |
subject | string | Yes | Maximum length: 500 Pattern: \S |
body | string | Yes | Maximum length: 20000 Pattern: \S |
include_email_attachments | boolean | No |
Step example
{
"type": "send_email",
"name": "Email result",
"description": "",
"fields": {
"to": "ops@example.com",
"subject": "Order results",
"body": "{{matchedProducts}}",
"include_email_attachments": false
}
}fetch_email
Read the Run as user’s connected mailbox. Move processed messages to processed_folder.
Uses the run_as user’s connected mailbox. Use folder names or paths recognized by that mailbox. Processed messages move to processed_folder.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
folder | string | Yes | Maximum length: 500 Pattern: \S |
processed_folder | string | Yes | Maximum length: 500 Pattern: \S |
failed_folder | string | No | Maximum length: 500 |
keyword | string | No | Maximum length: 500 |
sender | string | No | Maximum length: 500 |
recipient | string | No | Maximum length: 500 |
body_keyword | string | No | Maximum length: 500 |
single_file | boolean | No |
Step example
{
"type": "fetch_email",
"name": "Read orders",
"description": "",
"fields": {
"folder": "Inbox",
"processed_folder": "Processed",
"failed_folder": "Failed",
"keyword": "Order",
"single_file": false
}
}ai_answer
Direct AI answers; uses answer context by default.
Use an exact model from GET /api/v1/tasks/authoring-options. fields.prompts contains prompt, output, model and response. Retain returned step and prompt IDs to preserve hidden settings across renames. Edited shared instructions are copied, not modified. question_ids is compatibility input only; new AI steps do not need instruction IDs. These types share a shape but are not interchangeable aliases.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
prompts | array | Yes | Items: 1–100 |
prompts[].id | string | No | Retain the returned instruction ID when editing, including when renaming its output. Pattern: ^[a-fA-F0-9]{24}$ |
prompts[].prompt | string | Yes | Maximum length: 200000 Pattern: \S |
prompts[].output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
prompts[].model | string | Yes | Exact model name from the model catalog, for example gpt-5.5. Maximum length: 200 Pattern: \S |
prompts[].response | string | Yes | Values: string, json, foreach, code, media, task, list |
Step example
{
"type": "ai_answer",
"name": "Match to product codes",
"description": "",
"fields": {
"prompts": [
{
"prompt": "Match the order lines to product codes in {{priceList}}. Return JSON.",
"output": "matchedProducts",
"model": "gpt-5.5",
"response": "json"
}
]
}
}ai_agent
Recommended for new agent tasks; uses agent context by default.
Use an exact model from GET /api/v1/tasks/authoring-options. fields.prompts contains prompt, output, model and response. Retain returned step and prompt IDs to preserve hidden settings across renames. Edited shared instructions are copied, not modified. question_ids is compatibility input only; new AI steps do not need instruction IDs. These types share a shape but are not interchangeable aliases.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
prompts | array | Yes | Items: 1–100 |
prompts[].id | string | No | Retain the returned instruction ID when editing, including when renaming its output. Pattern: ^[a-fA-F0-9]{24}$ |
prompts[].prompt | string | Yes | Maximum length: 200000 Pattern: \S |
prompts[].output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
prompts[].model | string | Yes | Exact model name from the model catalog, for example gpt-5.5. Maximum length: 200 Pattern: \S |
prompts[].response | string | Yes | Values: string, json, foreach, code, media, task, list |
Step example
{
"type": "ai_agent",
"name": "Match to product codes",
"description": "",
"fields": {
"prompts": [
{
"prompt": "Match the order lines to product codes in {{priceList}}. Return JSON.",
"output": "matchedProducts",
"model": "gpt-5.5",
"response": "json"
}
]
}
}transcribe_audio
Transcribe emailAttachments with fields.transcriptions (model and output). Saved question_ids remain compatibility input.
Use fields.transcriptions with model and output for each transcription. Models must have type 3 in authoring-options. Reads include instruction IDs: retain these on edits. Consumes audio in emailAttachments and returns text under output, plus outputQuality. question_ids is compatibility input only; new steps do not need instruction IDs.
Fields
| Field | Type | Required | Details |
|---|---|---|---|
transcriptions | array | Yes | Items: 1–100 |
transcriptions[].id | string | No | Pattern: ^[a-fA-F0-9]{24}$ |
transcriptions[].model | string | Yes | Maximum length: 200 Pattern: \S |
transcriptions[].output | string | Yes | Output tag name without {{braces}}. Maximum length: 100 Pattern: ^(?!__proto__$|constructor$|prototype$)[A-Za-z_][A-Za-z0-9_]*$ |
Step example
{
"type": "transcribe_audio",
"name": "Transcribe voicemail",
"description": "",
"fields": {
"transcriptions": [
{
"model": "whisper-1",
"output": "audioTranscription"
}
]
}
}end
End the task run.
fields must be an empty object. This ends the whole task run, including when it is used inside a loop.
Fields
No fields. Supply fields: {}.
Step example
{
"type": "end",
"name": "Finish",
"description": "",
"fields": {}
}Complete task with named branches and a loop
Each child points to an earlier step by name. The true branch loops over orders; the false branch records that none were found. Replace run_as and notification emails before saving.
{
"name": "Process order list",
"active": false,
"schedule": {
"type": "manual"
},
"run_as": "user@example.com",
"notification": "errors",
"notification_emails": [
"ops@example.com"
],
"log_reference": "Order processing",
"steps": [
{
"type": "code",
"name": "Prepare orders",
"fields": {
"code": "return [{ number: \"PO1001\" }];",
"output": "orders",
"format": "json"
}
},
{
"type": "if_statement",
"name": "Has orders",
"fields": {
"code": "return {{orders}}.length > 0;",
"output": "hasOrders"
}
},
{
"type": "for_each",
"name": "Each order",
"parent": "Has orders",
"branch": "true",
"fields": {
"list": "orders",
"item": "order",
"index": "orderIndex",
"max_iterations": 1000,
"continue_on_error": false,
"output": "orderResults"
}
},
{
"type": "log_response",
"name": "Record order",
"parent": "Each order",
"fields": {
"body": "{{order.number}}"
}
},
{
"type": "log_response",
"name": "No orders",
"parent": "Has orders",
"branch": "false",
"fields": {
"body": "No orders to process."
}
}
]
}Schedule and task settings
Schedule times use the scheduler server timezone. Daily requires time; weekly also requires day_of_week; monthly requires day_of_month; yearly also requires month. Interval requires interval_minutes, start_time and stop_time, with stop after start on the same day. Manual and fixed interval types need only type. Per-task timezones are not supported.
| Field | Type | Required | Details |
|---|---|---|---|
type | string | Yes | Values: manual, yearly, monthly, weekly, daily, hourly, every_15_minutes, every_5_minutes, every_minute, interval |
time | string | No | HH:mm in the existing scheduler server timezone. Per-task timezone is not supported. Pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$ |
month | integer | No | Minimum: 1 Maximum: 12 |
day_of_month | integer | No | Minimum: 1 Maximum: 31 |
day_of_week | integer | No | 0 = Sunday, 6 = Saturday Minimum: 0 Maximum: 6 |
interval_minutes | integer | No | Minimum: 1 Maximum: 1440 |
start_time | string | No | HH:mm in the existing scheduler server timezone. Per-task timezone is not supported. Pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$ |
stop_time | string | No | HH:mm in the existing scheduler server timezone. Per-task timezone is not supported. Pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$ |
retry_until | string | No | Same-day retry deadline for daily, weekly, monthly and yearly schedules, inclusive. Defaults to 23:59. Runs retry from the first step after 5, 15, then every 30 minutes until a completed successful log starting on or after the scheduled time exists, or the deadline passes. Pattern: ^([01][0-9]|2[0-3]):[0-5][0-9]$ |
Notification values are errors or all. Set notification_emails: [] to disable delivery. log_reference supports existing {{tags}}. See the Tasks API for the complete task request schema.
Required schedule fields
| Type | Required fields |
|---|---|
| manual | type |
| yearly | type, month, day_of_month, time |
| monthly | type, day_of_month, time |
| weekly | type, day_of_week, time |
| daily | type, time |
| hourly | type |
| every_15_minutes | type |
| every_5_minutes | type |
| every_minute | type |
| interval | type, interval_minutes, start_time, stop_time |
Inputs and outputs
{
"syntax": "{{outputName}} or {{outputName.property}}; loop list uses outputName without braces.",
"fetch_email": {
"emailAttachments": "array of stored attachment paths",
"emailBody": "email HTML/text",
"emailSender": "sender email",
"emailSubject": "subject",
"emailSendDate": "message date"
},
"transcribe_audio": "Reads emailAttachments; writes each configured output as text and outputQuality as an object. audioTranscription remains an alias for the first result.",
"code_and_http": "Writes the return value under fields.output. Its structure depends on your code or endpoint.",
"ai": "Prompts run in list order; later prompts may use earlier outputs. response json requests parsed JSON; specify the required properties in prompt text.",
"loops": "fields.item and fields.index are available to loop children.",
"scope": "Branch outputs are available only if that branch ran. Project API/environment tags require project configuration and are not implied by text references."
}
Validation and errors
Checks schema, saved references, project permissions, model catalog and edit constraints. Does not execute steps or contact external providers. Independent schema errors are returned together; resolve these before semantic checks.
Validation success returns {"valid":true,"issues":[],"warnings":[...]}. Errors use HTTP status codes below and JSON Pointer field paths. Validation does not save or run a task.
{
"error": "Task validation failed",
"code": "invalid_request",
"issues": [
{
"path": "/steps/0/fields/output",
"code": "required",
"message": "output is required",
"step": "Prepare orders"
}
]
}{
"200": "Read, update or successful validation",
"201": "Created",
"400": "Invalid request; inspect issues",
"401": "Authentication required",
"403": "Permission denied",
"404": "Task not found in project",
"409": "Stale revision, queued/running task or conflicting saved configuration"
}