Stage scope: this stage covers only what Build and Manage Wix Automations lists; do not perform anything marked "Later stages only", and follow the instruction attached to each 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).
Every call this skill needs, as a public REST endpoint (base https://www.wixapis.com) and the
matching @wix/automations SDK method. Docs live under
https://dev.wix.com/docs/api-reference/business-management/automations/ — append .md to any
docs URL to get raw markdown. When a field name here and the docs disagree, the docs win.
TL;DR
INACTIVE → Get read-back; activate only when asked. Updates need the current
revision and are live on an active automation. Procedures (create, update, activate, read-back
— builder drafts are invisible publicly): Automations Validation and Persistence §3.SCOPE.CRM.SETUP-AUTOMATIONS) for every
Automations method below. Email steps are added in the automations builder, so no Manage
Email Marketing (SCOPE.DC-PROMOTE.EMAIL-MARKETING) scope is needed here.
Entity lookups in other verticals need that vertical's read scope
(Automations Entity and Provider Configuration (topic guide not yet published; consult the Automations API reference)).Authorization: <token> header — an OAuth app access token (client_credentials via
Create Access Token) or an account API key the site owner generated with the needed scopes.wix-site-id: <metaSiteId> on every call (all calls
here are site-level); never together with wix-account-id. OAuth app tokens are already bound
to one site instance.import { automationsV2, triggerCatalog, actionCatalog, activations } from '@wix/automations', used through a createClient Wix client with an auth strategy.metaSiteId once and use it for every call, read-back and
link. Ask the user to confirm it before the first write only when more than one site is in
context or the request doesn't make clear which; a site fixed by the request or session is
confirmed. If anything points at another site, stop.automationsV2) — base /automations-service/v2/automations| Purpose | REST | SDK |
|---|---|---|
| Validate | POST https://www.wixapis.com/automations-service/v2/automations/validate | validateAutomation(automation, options) |
| Create | POST https://www.wixapis.com/automations-service/v2/automations | createAutomation(automation) |
| Get | GET https://www.wixapis.com/automations-service/v2/automations/{automationId} | getAutomation(automationId) |
| Update | PATCH https://www.wixapis.com/automations-service/v2/automations/{automation.id} | updateAutomation(_id, automation) |
| Delete | DELETE https://www.wixapis.com/automations-service/v2/automations/{automationId} | deleteAutomation(automationId) |
| Query | POST https://www.wixapis.com/automations-service/v2/automations/query | queryAutomations(query) |
{automation, validationSettings?{actionIds[], skipProviderValidations}} → {status: VALID|VALID_WITH_WARNINGS|INVALID, triggerValidationErrors[], actionValidationErrors[]}. The main oracle; send the full object.
Reading errors: Automations Validation and Persistence §2.{automation} with name, origin: "USER", configuration{status, trigger{appId, triggerKey}, rootActionIds, actions} → created automation (has id, revision). Does NOT
validate. Always status: "INACTIVE"; don't send settings.automation. Use for read-back after every write and before every update.
trigger.overrideSchema and appDefinedInfo.overrideOutputSchema come back only when you
request them: fields: ["OVERRIDE_SCHEMA"] (REST ?fields=OVERRIDE_SCHEMA). Without it their
absence is not data loss (Create's response omits them too).
Request overrides before complete-object updates and status changes too, not just creation read-back.{automation} incl. id and current revision → updated automation (revision
+1). Does NOT validate. Send the complete merged name + configuration, plus origin and
settings exactly as fetched — an Update without them fails INVALID_ORIGIN_TYPE. A
fieldMask (if your client exposes one) only selects what changes — set it to
configuration,name (what the builder sends); it doesn't exempt you from sending origin /
settings. A stale revision is rejected. Changes are LIVE when status is ACTIVE. A success
response and a revision bump do not prove the change landed — merge, conflict handling and
read-back comparison: Automations Validation and Persistence §3.
Capture the returned id: creating a site override of a preinstalled automation can change it.{}. Irreversible; only on explicit user request.{query{filter, sort, cursorPaging{limit ≤ 500, cursor}}} → automations[],
pagingMetadata.cursors.next. Returns only automations of apps installed on the site (incl.
overridden preinstalled ones), and never unpublished builder drafts. Full objects are large —
keep only id, name, configuration.status, configuration.trigger. If a filtered query fails on
a site with many automations, page unfiltered and filter locally.Automation object fields and limits (name ≤ 100 for the builder, description ≤ 2000,
origin, settings, configuration): Automations Graph and Data Model §1.
Create/Update accept configuration.trigger.automationConfigMapping for scheduled/custom/webhook
configuration even where the docs omit it; use Automations Trigger Configuration / Automations Schemas and Scheduling.
triggerCatalog)| Purpose | REST | SDK |
|---|---|---|
| Triggers on this site | POST https://www.wixapis.com/v1/triggers/resolve | resolveTriggers(options) |
| Global catalog | POST https://www.wixapis.com/v1/triggers/query | queryTriggers(query) |
| One trigger | GET https://www.wixapis.com/v1/triggers/apps/{appId}/keys/{triggerKey} | getTriggerByAppIdAndKey(identifiers, options) |
| Dynamic payload schema | POST https://www.wixapis.com/v1/triggers/dynamic_schema | getTriggerDynamicSchema(appId, options) |
| Identity enrichment | POST https://www.wixapis.com/v1/triggers/identities_schema | getIdentitiesSchema() |
{basicFieldsOnly?, appId?, query{filter, paging{limit, offset}, fields?}} →
results[], paging. Installed apps only. basicFieldsOnly: true for browsing (drops payload
schema, config schema, filters).{query{filter, …}} → results[] (filterable: appId, triggerKey,
displayName, implementedMethods.*). Includes apps NOT installed on the site — never build on
a trigger Resolve didn't return.trigger with payloadDataSchema, filters[], automationConfigSchema,
implementedMethods. The preferred way to hydrate a shortlisted trigger.{appId, triggerKey, selectedFilterOptions[{fieldKey, values[]}] (≤ 5)} →
dynamicSchema. Only when implementedMethods.getDynamicSchema is true, and only after the
filters that drive it are chosen — no filter chosen ⇒ form answers are unknown, not absent
(request and merge: Automations Trigger Configuration §5).{} → identitiesSchema{contact, member, …} — shape of the contact /
member objects added when payload fields carry identityType.Trigger objects have no free-text description and display names are ambiguous — decide by the payload schema (Automations Trigger Configuration §2).
actionCatalog)| Purpose | REST | SDK |
|---|---|---|
| Actions on this site | POST https://www.wixapis.com/v1/actions/resolve | resolveActions(options) |
| Global catalog | POST https://www.wixapis.com/v1/actions/query (and /query-latest) | queryActions(query), queryLatestActions |
| Version active on the site | GET https://www.wixapis.com/v1/actions/apps/{appId}/keys/{actionKey} | getRuntimeAction(identifiers) |
| Latest version | GET https://www.wixapis.com/v1/actions/latest/apps/{appId}/keys/{actionKey} | getLatestAction(identifiers, options) |
| Dynamic input schema | POST https://www.wixapis.com/v1/actions/dynamic-input-schema | getActionDynamicInputSchema(appId, options) |
| Dynamic output schema | POST https://www.wixapis.com/v1/actions/dynamic-output-schema | getActionDynamicOutputSchema(appId, options) |
{query{filter, paging{limit, offset}, fields?}} → actions[], paging. Offset
paging only (cursorPaging is rejected). Entries carry full inputSchema, outputSchema,
uiSchema — large. Filter by appId/actionKey, page ≤ 25.action. Use this schema when configuring for this site. Latest version
is for reference only.{appId, actionKey, inputMapping} → {inputSchema, uiSchema}. Call when an
input property has updateSchemaOnChange: true (no public getDynamicInputSchema flag);
re-call after changing such a field.{appId, actionKey, inputMapping} → outputSchema; bulk
(bulkGetActionDynamicOutputSchemas, POST /v1/actions/bulk/dynamic-output-schema, ≤ 20 items) →
results[]{itemMetadata{success, error}, outputSchema}. Only after that action's mapping is
final. For wix_automations-llm_call fields defined by your output configuration, declare an override directly (Automations Schemas and Scheduling §3); do not call this SPI to discover fields you chose yourself. For other upstream actions whose configured output is needed, this is a read-only discovery call (no public flag says which are dynamic); an error does not establish additional fields — keep the static outputSchema.
Merge into the static schema. A failed bulk item = unknown schema, not empty.POST https://www.wixapis.com/v1/actions/generate-input-mapping-from-intent)
is AI-backed — don't call it. For actions you can't map from their schema, tell the user they can't be configured through the API here and can be set up in the automations builder.Action objects: appId, actionKey, displayName, description, inputSchema, outputSchema,
interfaceConfiguration{type: GENERIC\|WIDGET_COMPONENT, genericOptions.uiSchema},
implementedMethods{validateConfiguration, getQuotaInfo} (public). Resolve Actions has no
basicFieldsOnly option (only Resolve Triggers does). Mapping rules: Automations Action Configuration.
activations)POST https://www.wixapis.com/automations/v1/events/test-automation,
testAutomation(identifierType, options): {identifierType: "AUTOMATION", automationIdentifier{automationId}, payload} → activationId. Runs every action for real
(skips delays, works on INACTIVE) — explicit user authorization only; payload, consent and
reporting: Automations Validation and Persistence §5.resolveTriggers({basicFieldsOnly: true, query: {paging: {limit: 25, offset: N}}}). Actions: resolveActions with small pages; keep only appId, actionKey/
triggerKey, displayName, description, interfaceConfiguration.type. Field projection (fields) may
be ignored — strip locally in code before anything reaches your reasoning context. Even with
basicFieldsOnly, 100 triggers is ~100 KB: keep pages ≤ 25 when results land in your context.updateSchemaOnChange field.{"appId": "...", "actionKey": "..."}). Full schemas only for the chosen few.appId, triggerKey/actionKey, and $in on the keys (both
Resolves); on Resolve Triggers also displayName $contains / $in (inside $or too) and
triggerKey $startsWith. Resolve Actions rejects displayName filters — search names
locally. A rejected filter → fall back to small pages.sort: [{fieldName: "id"}] fails with SORT_PARSER_ERROR on both Resolves.
Unsorted offset pages can overlap: page until paging.total, de-duplicate by appId+key,
and count distinct entries. An action or trigger is proven missing only after a complete,
de-duplicated scan (distinct count = paging.total). Report the evidence ("scanned N distinct
of paging.total N"); without that proof say it was "not found in the installed catalog",
never that it is not installed. Either way, list the closest related entries you did find with
their returned appId + key and display name — don't omit them, and don't fetch their schemas
unless the user asks. A shortcut:
take the appId from a related action, then Resolve by appId.Discovery hints:
send-message (not inbox-send-message); a note about a contact in
the site owner's Inbox, nothing sent to the contact = inbox-send-message ("Show in Inbox");
email (added by the user in the automations builder here) to anyone, incl. the site
owner = triggered-emails (never the deprecated send-mail / "Get an email"); task =
createTask; labels = addLabelsToContact / remove_labels_to_contact; create a contact =
contacts-create_contact (for triggers whose payload has no contact, e.g. webhooks).booking_canceled vs bookings_canceled; new Wix Forms app vs legacy
"Form submitted"). Compare payload schemas and filters; prefer the one whose entities you can
actually find on the site (Automations Entity and Provider Configuration (topic guide not yet published; consult the Automations API reference)).description (e.g. paymentStatus
NOT_PAID / PAID). Read descriptions before mapping user words; never invent enum values.Node N may read the trigger payload + each ancestor's output (under its namespace) + variables + identity enrichment. Recipe and fetch order: Automations Graph and Data Model §4.
Entity ids (forms, labels, services, pipeline stages…): resolve them with the owning vertical's public API, following that vertical's API reference, or ask the user for the exact entity. Never save a display name, invent an id or guess an endpoint.
Not public or not available through the general Automations API:
INACTIVE; the user activates. Builder drafts are invisible.Last updated: 29 October 2026