integration.yaml Schema
Complete reference for the integration.yaml manifest format used in HeadlessOps automations. Covers trigger types, step routing, npm package dependencies, webhook authentication, HTML responses, and synchronous response modes.
integration.yaml Full Schema
name: my-automation # Required. Unique slug for this automation. kebab-case.
description: "What it does" # Required. One-line human-readable description.
packages: # Optional. npm packages installed before every run.
- zod
- dayjs@2.0
- lodash@^4.17.21
trigger:
type: webhook # Required. One of: webhook | schedule | manual
# --- Webhook-only fields ---
method: POST # Optional. HTTP method filter: ANY | POST | GET | PUT (default: ANY)
response_mode: immediate # Optional. immediate (default) | synchronous
auth: # Optional. Protect the webhook with a secret header.
header: x-api-key # Required if auth present. HTTP header name to check.
credential: MY_WEBHOOK_KEY # Required if auth present. Credential name whose value must match.
# --- Schedule-only fields ---
cron: "0 9 * * 1-5" # Required when type is schedule.
steps:
- id: step_one # Required. Unique snake_case identifier. Must match .ts filename.
name: "Fetch Contact" # Required. Human-readable label.
description: "Fetches contact details from CRM" # Required. One-line description.
file: step_one.ts # Required. Must equal {id}.ts.
icon: database # Optional. UI icon slug (database, mail, globe, zap, code, search).
credentials: # Optional. List of credential names used (for UI display).
- MY_API_KEY
input: # Optional. Key-value map passed as `input` object to the step.
email: "${{ trigger.body.email }}"
api_url: "${{ config.API_BASE_URL }}"
output: # Optional. Declares the return value shape (for UI/docs).
contact_id: string
contact_name: string
on_success: step_two # Optional. Step id to route to on success.
on_failure: handle_error # Optional. Step id to route to on error.
continue_on_error: false # Optional. If true, on_success runs even when step errors.
routes: # Optional. Conditional routing (turns step into a condition node).
- when: "${{ steps.step_one.output.status }} == 'active'"
next: step_two
- default: handle_inactiveTop-Level Field Reference
| Field | Required | Type | Description |
|---|---|---|---|
name | ✅ | string | Unique kebab-case slug for this automation. |
description | ✅ | string | One-line human-readable description. |
packages | ❌ | string[] | npm package specifiers installed into the integration's isolated environment before every run. Synced automatically to the integration's requirements on each push. |
trigger | ✅ | object | Defines how the automation is triggered. |
steps | ✅ | array | Ordered list of step definitions. |
The packages Field — Dependency Management via YAML
The packages field lets you declare all npm dependencies directly in integration.yaml. Every time you push files to the platform, the packages array is automatically parsed and synced to the integration's requirements — no separate API call needed.
name: data-pipeline
description: "Pulls records from an API, processes with lodash, stores results"
packages:
- zod@^3.23
- dayjs@2.0
- lodash@^4.17.21This is the recommended way to manage dependencies for most integrations. The packages field supports standard npm specifier formats:
| Format | Example | Behaviour |
|---|---|---|
| Latest | lodash | Installs the newest available version |
| Pinned | dayjs@2.0.0 | Exact version lock — recommended for production |
| Range | zod@^3.23 | Semver-compatible version range |
| Tag | lodash@latest | Specific dist-tag |
Note: Git URLs, local paths, and tarball URLs are blocked for security. Attempting to use them returns a
400 Bad Requesterror.
How Sync Works
When you push integration.yaml (via integration_files_push, integration_files_push_run, or integration_files_deploy), the platform:
- Parses the
packagesarray from the YAML. - Updates the integration's
requirementsfield in the database to match. - Installs the resolved packages into an isolated environment before the next run.
This means your YAML file is the single source of truth for both the automation logic and its dependencies. No separate integrations_update call is required to keep packages in sync.
Trigger Field Reference
| Field | Applies to | Values | Default | Description |
|---|---|---|---|---|
type | all | webhook | schedule | manual | — | Required. |
cron | schedule | cron string | — | Required for schedule. |
method | webhook | ANY | POST | GET | PUT | ANY | HTTP method filter. |
response_mode | webhook | immediate | synchronous | immediate | synchronous waits for run and returns ctx.output(). |
auth.header | webhook | string | — | Header name to check for the secret. |
auth.credential | webhook | credential name | — | Credential whose value must match the header. |
Step Field Reference
| Field | Required | Type | Description |
|---|---|---|---|
id | ✅ | string | Unique snake_case identifier. Must match the .ts filename. |
name | ✅ | string | Human-readable label shown in logs and UI. |
description | ✅ | string | One-line description of what this step does. |
file | ✅ | string | TypeScript filename (e.g. step_one.ts). Must equal {id}.ts. |
icon | ❌ | string | Icon slug: database, mail, globe, zap, code, search. |
credentials | ❌ | string[] | Credential names used by this step (informational, for UI). |
input | ❌ | map | Key-value pairs passed as the input object. Supports ${{ }} expressions. |
output | ❌ | map | Declares the return value shape (e.g. field_name: string). |
on_success | ❌ | step id | Step to route to on success. Overrides linear order. |
on_failure | ❌ | step id | Step to route to on error. |
continue_on_error | ❌ | boolean | If true, on_success runs even when the step errors. |
routes | ❌ | array | Conditional routing rules. |
Warning: A step missing any of the four required fields (
id,name,description,file) will be silently skipped at runtime with no error message.
Conditional Routing
steps:
- id: check_status
name: Check Status
description: Routes based on contact status
file: check_status.ts
routes:
- when: "${{ steps.check_status.output.status }} == 'active'"
next: send_welcome
- when: "${{ steps.check_status.output.status }} == 'churned'"
next: send_winback
- default: log_unknownSynchronous Webhook Response
trigger:
type: webhook
response_mode: synchronousDefault (JSON):
export async function run(input: Record<string, any>, ctx: StepContext) {
const result = { status: "ok", id: input.id };
ctx.output(result); // returned to the webhook caller as JSON
return result; // available to downstream steps
}HTML Response:
To return HTML from a synchronous webhook, include a __html key in the value passed to ctx.output(). The platform automatically sets Content-Type: text/html on the response:
export async function run(input: Record<string, any>, ctx: StepContext) {
const html = `<!DOCTYPE html>
<html>
<head><title>Result</title></head>
<body>
<h1>Record Processed</h1>
<p>ID: ${input.record_id}</p>
<p>Status: OK</p>
</body>
</html>`;
ctx.output({ __html: html });
return { status: "ok" };
}Note: When
__htmlis present, no other top-level keys are included in the response body — only the HTML string is returned.
pinned-trigger-payload.json
Pin a static trigger payload for manual and test runs. The file must mirror the exact runtime structure:
| Trigger type | Pinned payload shape |
|---|---|
webhook | { "query": {...}, "body": {...}, "headers": {...} } |
manual | Flat object matching expected trigger.body shape |
Related
- Custom npm Packages — detailed guide on dependency management, caching, and security
- TypeScript ctx API — available context methods in step scripts
- MCP Tools Reference — push-run modes, file deployment tools
- Template Expressions —
${{ }}syntax reference
MCP Setup Overview
Connect AI agents to HeadlessOps via the Model Context Protocol. Full reference for MCP tools, OAuth 2.1 authentication, workspace resolution, push-run execution modes, and synchronous run output.
TypeScript ctx API
Complete reference for the ctx object available in every step function