Stage scope: this stage covers only what Build and Manage Wix Automations lists; do not perform anything marked "Later stages only" or any workflow that needs a guide marked "not yet published". "Stage", "Later stages only" and "not yet published" describe how this skill is being rolled out; never mention them to the user. Explain a limit in product terms: what can't be done through the API here and where the user can do it instead (for example, in the automations builder).
TL;DR
rootActionIds has EXACTLY one id; every connection field holds AT MOST one id; no joins, no cycles, no orphans. Parallelism only via SPLIT; "both branches continue" = duplicate the downstream steps per branch (the builder caps an automation at 45 actions — count before duplicating).actions[k].id === k, a fresh uuid v4, a unique namespace (except variable steps, which share setVariable), and ONLY its own type's *Info object.var("...")) only its node's aggregated payload schema: trigger payload + identity enrichment + outputs of its ANCESTOR steps.In this stage you create only APP_DEFINED steps. The other step types below are documented so you can read and preserve existing automations, not to author them here.
| Field | Rules |
|---|---|
id, revision | Read-only. revision MUST be sent back on Update Automation (§6). |
name | Required, 1–100 chars (API allows 500; the builder holds 100); the business outcome ("Send welcome email to new subscribers"). |
description | Optional, ≤2000 chars. |
origin | Required on create, immutable. USER for anything you create. APPLICATION/PREINSTALLED carry update locks (§4 of Automations Feasibility and Planning (not yet published)). |
settings | Locks for APPLICATION/PREINSTALLED (readonly, actionSettings, …). Never set it on create; on Update send it back exactly as fetched. |
configuration.status | Required, ACTIVE | INACTIVE. Create INACTIVE; activate only on request. |
configuration.trigger | {appId, triggerKey, filters[], scheduledEventOffset?, overrideSchema?, automationConfigMapping?} — Automations Trigger Configuration. |
configuration.rootActionIds | Exactly one action id. |
configuration.actions | Map actionId → Action. |
Action (common fields):
id — uuid v4, equal to its map key.type — APP_DEFINED, CONDITION, CODE_CONDITION, DELAY, RATE_LIMIT, SET_VARIABLES, SPLIT (the last two are not yet in the public API docs, but the builder supports them — Automations Delays Variables and Branches (not yet published)). NEVER UNKNOWN_ACTION_TYPE, NEVER MERGE.namespace — 1–100 chars, unique except the shared setVariable namespace (§3). Outputs of this step appear under it.displayName — optional but always set it: 1–60 chars, sentence case, purpose-specific (§7 of Automations Delays Variables and Branches (not yet published)). Absent → the canvas shows the catalog name.skipActionExpression — absent (runs) or exactly "{{true}}" (skipped), the only value the builder writes. A skipped step adds NO outputs downstream (§4).*Info matching type: appDefinedInfo, conditionInfo, codeConditionInfo, delayInfo, rateLimitInfo, setVariablesInfo, splitInfo.rootActionIds = [oneId], and no action may point at the root. The builder draws only rootActionIds[0]; extra roots are saved but invisible.appDefinedInfo.postActionIds, delayInfo.postActionIds, rateLimitInfo.postActionIds, setVariablesInfo.postActionIds, conditionInfo/codeConditionInfo.truePostActionIds / falsePostActionIds each hold 0 or 1 id (API maxItems 1).[], never omit the field.MERGE type and conditionInfo.mergeActionId, but the canvas cannot draw them (MERGE nodes never finish loading). Never create either; when you read an automation that has them, preserve them untouched and don't add more.appId + triggerKey exist in the site's trigger catalog (a missing trigger can leave every node loading).actions[k].id === k for every entry.triggerKey string (it is the trigger node's id), and the builder's synthetic ids <id>true, <id>false, <id>-end, <id>true-end. Duplicates crash the layout. Generate every id as a fresh uuid v4 in code; never reuse ids from these references.*Info. The canvas ignores type when finding children and takes the first present of appDefinedInfo → delayInfo → rateLimitInfo → setVariablesInfo → condition — even an empty leftover appDefinedInfo: {postActionIds: []} on a CONDITION hides both branches.appId + actionKey match the site's action catalog, else the node shows "Action not available".Later stages only: not available in stage 2; this section is published in stage 3.
In this stage: put independent actions ("create a task and add a label") in one linear chain A → B → C, most time-sensitive first.
Later stages only: not available in stage 2; this section is published in stage 3.
In this stage: add only the steps the user asked for. Audience or copy framing ("a VIP follow-up for high-value customers") is content inside one action, not a condition.
Use the builder's own convention (it derives new indexes from the trailing number):
| Type | Namespace |
|---|---|
| APP_DEFINED | <actionKey>-<N> (e.g. triggered-emails-3) |
| CONDITION and CODE_CONDITION | CONDITION-<N> |
| DELAY / SPLIT / RATE_LIMIT | <TYPE>-<N> (e.g. DELAY-2, SPLIT-5, RATE_LIMIT-1) |
| SET_VARIABLES (and existing code-variable steps) | always the literal setVariable (§4 of Automations Delays Variables and Branches (not yet published)) |
N = 1 + the largest number after the last - among all the automation's namespaces (one counter shared across every step type — e.g. DELAY-1 then createTask-2). A namespace with no trailing number (setVariable) doesn't count: if it is the only one, the next N is 1. A CODE_CONDITION keeps CONDITION-<N>. The builder never rewrites an existing namespace — on update keep every existing one as is. Variable and existing code-variable steps intentionally share setVariable; their distinct property keys are merged. For other output-producing actions, never reuse a namespace — the later output overwrites the earlier one.
var() can read at a nodeThis section owns the rule. Build one JSON Schema object per node, in code, from the root down its own branch, from public schema APIs (calls: Automations API Catalog §3–§4).
payloadDataSchema (custom/webhook triggers: trigger.overrideSchema instead, §3 of Automations Schemas and Scheduling (not yet published)). If the trigger implements dynamic schema, call Get Trigger Dynamic Schema with the SELECTED (saved) filter options and MERGE its properties over the static ones (Automations Trigger Configuration §5); before filters are chosen, dynamic fields are UNKNOWN, not absent. Trigger fields are un-prefixed: var("orderId").identityType: "contact" or "member", a root-level object is added, keyed by that field's namespace annotation when it has one, else its (deprecated) name annotation, else the identity type (contact / member). Shape: Get Identities Schema (identitiesSchema.properties.contact / .member). Both stay valid: var("contactId") and var("contact.name.first"); also e.g. var("contact.email"), var("member.profile.nickname"). A field annotated name: "post_author_member" (some Blog / File Share triggers) is enriched as var("post_author_member.profile.nickname") — two member ids on one trigger give two objects; use the key the field declares (member.* does not exist there). Other identity types (e.g. visitor) add no object; webhook/custom triggers (override schema) get none. The builder does not enrich identity fields of action outputs — don't read contact.* that only an action output would provide.properties[<namespace>]: catalog outputSchema, with overrideOutputSchema.properties merged over it, and — when the action implements dynamic output — Get Action Dynamic Output Schema (called with that step's final inputMapping) merged over that: var("triggered-emails-3.messageId").outputSchema) of non-skipped ancestor SET_VARIABLES / code-variable (namespace: "setVariable") steps, merged under setVariable: var("setVariable.<key>") (§4 of Automations Delays Variables and Branches (not yet published)).Scope rules:
skipActionExpression: "{{true}}") contributes nothing; never skip a step whose outputs a later step reads.inputMapping → its dynamic output schema (if any) → add it to its children's schema.var() path MUST exist in this node's aggregated schema with a compatible type — never reason from a raw trigger or action schema alone, and never invent a field. Copy keys from the schema (titles/labels are not keys); arrays cannot be traversed by path (Automations Mapping Expressions §5).var("contact.locale") into the email's dynamic content; no separate "language" field is needed.Syntax of expressions and the allowed function list: Automations Mapping Expressions.
The simplest shape: one trigger and a chain of APP_DEFINED actions linked by postActionIds.
The trigger and action identities below are the Contacts "new contact created" trigger and the
Tasks "create task" action; confirm them, and each action's input keys, against the site's
catalog before use. Generate fresh uuid v4 action ids.
Why it's valid: one parentless root; each action has at most one successor and one parent; ids
equal their keys; namespaces are unique per §3; inputMapping keys come from the input schema;
every var() path is in that node's aggregated schema; status is INACTIVE.
Later stages only: not available in stage 2; this section is published in stage 3.
Create INACTIVE (your "draft"); activate only on request. Create procedure and read-back: Build and Manage Wix Automations — included validation procedure §3; calls: Automations API Catalog §2.
Later stages only — not in stage 2: Update: Get → change only what was asked, keep every other node byte-for-byte → Validate → Update with the full merged object + revision, origin and settings as fetched; on an ACTIVE automation the change is live — confirm first. Locks: §4 of Automations Feasibility and Planning (not yet published).
Script the graph/id/namespace/var() items of Build and Manage Wix Automations — included validation procedure §4 (items 1–4 and 11 — the rules of §2–§4 above: one parentless root, RATE_LIMIT only as that root, ≤1 id per connection, one parent each, no cycles/orphans/MERGE/mergeActionId/UNKNOWN_ACTION_TYPE, keys = ids, globally unique uuid v4s incl. SPLIT path ids, triggerKey and <id>true/false/-end, own *Info only, §3 namespaces unique except setVariable, every var() in THAT node's aggregated schema). Also check that only user-requested conditions/delays exist; then Validate Automation must return no trigger or action errors.
Last updated: 13 October 2026