cypress.DOCS
Log inRegister
Cypress Docs
Developers

Automations

Build, try and submit your own automations, switch them, and read every run step by step.

TL;DRAI summary

This chapter explains how to set up automations that watch your vehicle records and automatically take actions, such as adding notes or updating prices. Cypress must approve and publish your automations before they run.

Dive deeper:

An automation watches your records and acts on them: a car listed 30 days gets a note or a new price, a deal that went quiet gets a task, a buyer's offer gets a follow-up. The API builds your organization's own automations with the rules the app uses, so an agent or an integration can propose one and try it on your cars. Cypress approves: nothing you write runs until a Cypress manager publishes it. Since 1.5.0.

ScopeGrants
automations:readYour automations, their versions and graphs, where a draft stands with Cypress, their runs and every step, and validating an automation
automations:writeEverything automations:read grants, plus creating, editing, saving drafts, dry runs, submitting, and switching automations on and off

Neither is a default scope. Automations is a product Cypress switches on per organization: until it is on, every call answers 403 AUTOMATIONS_NOT_ENABLED, asked before the scopes. Both an API key and a Connect Cypress token are accepted.

You see your own automations only. Cypress's own automations, which run for every organization or the ones a Cypress manager chose, are never listed, and neither are their runs.

Read your automations

curl "$BASE/api/v1/automations?active=true" -H "authorization: Bearer $TOKEN"
curl "$BASE/api/v1/automations/$AUTOMATION_ID" -H "authorization: Bearer $TOKEN"

An automation has at most two versions that matter: published, what runs, and draft, the work in progress, with its review (where it stands with Cypress). Reading one automation returns the graph of each (the nodes and the edges between them, as the editor stores them); the list leaves the graphs out. active says whether the published version runs on its trigger. The node types, their settings and what each needs are in GET /api/v1/automation/manifest.

Cypress's own automations (since 1.10.0). Every automation says whose it is: owner is ORGANIZATION (yours) or CYPRESS. Cypress runs a few of its own on every organization's cars (pricing, outlier alerts), and they can move a car with nobody at your organization doing anything: ?owner=cypress lists the ones that run on your records (switched on and published), ?owner=all lists them with yours. Reading one by id shows what runs, its published version and graph, with no draft and no runs (its runs are every organization's). They are never yours to change: a write, a switch or a run answers 404. The list without owner is yours alone, as before. Cypress's own read even when your organization's Automations product is off (they run on your cars either way); with it off, owner=all lists only Cypress's, and your own answer 403 AUTOMATIONS_NOT_ENABLED as before.

The manifest: every action as an act

GET /api/v1/automation/manifest describes Cypress to an automation engine that is not Cypress's (Himo, as Grove runs it): the records and their fields, the triggers, the lookups, every node with its settings, and what your credential can run. Since 1.5.0 every action an agent may run is an act: the same action as the app's actions, with its input as the node's settings, the refusal codes it may answer with, and how it dry runs. Each act has its node (named after its MCP tool, in capitals), and every read the API offers is a read.

An engine runs an act by calling the action's own REST route with your credential: the path filled from the input (the record the run is about fills its {id}), the rest as the body, ?dryRun=true on a dry run, and the step's Idempotency-Key otherwise, so a retried step acts once. A refusal (4xx, its code) is a step blocked for that reason; a 5xx is a failure. A write with no dry run of its own is never called on a dry run. A person's verbs (accepting below the floor, signing, approving a quarter) are not acts: an automation acts as an agent does.

The answer is cut to your credential's scopes, carries an ETag, and answers 304 to If-None-Match.

Build one

curl -X POST "$BASE/api/v1/automations" \
  -H "authorization: Bearer $TOKEN" -H "content-type: application/json" \
  -d '{
    "name": "Stale listing nudge",
    "category": "LISTING",
    "graph": {
      "nodes": [
        { "id": "start", "type": "trigger", "position": { "x": 0, "y": 0 },
          "data": { "nodeType": "ENTITY_TIME_ELAPSED", "label": "30 days listed",
                    "config": { "entity": "vehicle", "watchStatus": "LISTED", "duration": 30, "unit": "days" } } },
        { "id": "note", "type": "action", "position": { "x": 0, "y": 120 },
          "data": { "nodeType": "CREATE_TASK", "label": "Leave a note",
                    "config": { "note": "Listed 30 days: review the price" } } }
      ],
      "edges": [{ "id": "e1", "source": "start", "target": "note" }]
    }
  }'

curl -X PUT "$BASE/api/v1/automations/$AUTOMATION_ID/draft" \
  -H "authorization: Bearer $TOKEN" -H "content-type: application/json" \
  -d '{ "graph": { "nodes": [ … ], "edges": [ … ] } }'

A new automation has one draft and runs nothing. PUT .../draft saves the draft: it may be half wired, and the published version keeps running until Cypress publishes the draft in its place. PATCH renames an automation or changes its category or stages (the life stages it works in; Operation and Planning need the Planning product). The stages belong to the automation, not to a version: once Cypress has published one, they are part of what Cypress approved, and Cypress changes them.

What an organization's automation may contain

Your automations may use every trigger, condition and control node, and the actions that work on your own records: labels, tasks, CRM tags, notifications to your own people, the three price nodes, status changes, sales channels, fleet, exports and email. A node outside that list is refused with its reason, for example:

  • Delist takes a car off the market, withdraws its offers and tells the buyers, so a person does it in the app.
  • Request a valuation is a paid request, and Cypress orders those.
  • A notification goes to your own members, never to Cypress managers.
  • A label is your own or one of the platform's shared labels; a chained automation is one of your own; a fixed email recipient is one of your members, or a contact of your book who may be mailed.

Saving or submitting an automation that breaks one of these answers 403 POLICY_DENIED with findings, one per node.

Validate

curl -X POST "$BASE/api/v1/automations/$AUTOMATION_ID/validate" -H "authorization: Bearer $TOKEN"

Validate says what publishing would say, and writes nothing. errors would stop Cypress publishing it: the rules the app checks before an automation runs unattended (an export after a fan-out fetch, an automation that runs itself, a sales-channel step with no channel, a planning-stock step on an automation that works on planning stock) and the list above. warnings are the editor's advice and never block: a node parked to one side, a setting left empty. Send a graph in the body to judge it before saving.

Try it: dry runs

curl -X POST "$BASE/api/v1/automations/$AUTOMATION_ID/dry-run" \
  -H "authorization: Bearer $TOKEN" -H "content-type: application/json" \
  -d '{ "subjectIds": ["clx…", "clx…"] }'

A dry run tries a version (the draft by default; "version": "published" for the other) on your own records. Every step runs as the automation would and writes nothing: its result says what it WOULD have done, and a step the rules refuse shows as refused, with the reason. It answers 202 at once with one run per record:

{ "automationId": "…", "version": 2,
  "runs": [{ "id": "6f1c…", "subjectId": "clx…", "href": "/api/v1/automations/runs/6f1c…" }] }

Read each run at its href. It reads QUEUED until the worker starts it, then DRY_RUN once it is done; a run the worker does not go ahead with (a car outside the automation's stages, a record that is gone) is DRY_RUN too, with the reason in problems ("Not run: …").

  • On what. Vehicles for a vehicle automation; contacts, businesses or deals of your book for a CRM automation (at least one). An automation that fetches its own cars, or runs on a schedule, may be tried with no record. At most 25 per call.
  • As whom. As your organization's account admin (the earliest Fleet Manager or admin), exactly as the published automation will act. An automation switched off can still be tried.

Submit: Cypress approves

curl -X POST "$BASE/api/v1/automations/$AUTOMATION_ID/submit" -H "authorization: Bearer $TOKEN"

Submitting asks Cypress to publish the draft. It is checked first as publishing would check it (422 INVALID with findings when it could not be published), then waits for a Cypress manager: the draft's review.state reads SUBMITTED. The manager either:

  • publishes it: it replaces the published version and runs on its trigger while the automation is switched on (AUTOMATION.PUBLISHED), or
  • sends it back with a note on what to change (review.state reads SENT_BACK, with the note; AUTOMATION.SENT_BACK). Change the draft and submit it again.

Saving a submitted draft withdraws it from review: what Cypress would read is no longer what is there. Submit again when it is ready.

A published automation acts as your organization's account admin. It can do nothing that person could not do in the app: no price under the floor, the floor only for a Fleet Manager or an admin, a status move only as the app allows that role, email only to your own people and to contacts who may be mailed.

Switch on and off

curl -X POST "$BASE/api/v1/automations/$AUTOMATION_ID/deactivate" -H "authorization: Bearer $TOKEN"
curl -X POST "$BASE/api/v1/automations/$AUTOMATION_ID/activate"   -H "authorization: Bearer $TOKEN"

A switched-off automation runs nothing, and a run paused on a Wait step is cancelled when its wait ends. Switching it back on runs the version Cypress published.

  • Who may. An API key acts as your organization's admin. An app acting for a person needs that person to be a Fleet Manager or an admin. An agent drafts, tries, submits and switches automations off; switching one back on is a person's: 403 PEOPLE_ONLY.
  • Limits. At most 50 automations switched on and 200 in all (409 CONFLICT, with limit and count). Your automations start at most 500 runs an hour together; past that, a run is skipped until the hour has room.
  • Your records only. Whatever a graph says, your automation reads and acts on your own cars and your own book: a fetch is limited to your stock, and a chain reaches only your own automations.

Every write takes ?dryRun=true (it checks everything and writes nothing: not to be confused with POST .../dry-run, which tries the automation) and an Idempotency-Key, and is recorded in your audit log with the key, app or agent that made it.

Runs and steps

curl "$BASE/api/v1/automations/$AUTOMATION_ID/runs?status=PARTIAL" -H "authorization: Bearer $TOKEN"
curl "$BASE/api/v1/automations/runs/6f1c…"                        -H "authorization: Bearer $TOKEN"
curl "$BASE/api/v1/automations/runs/6f1c…/steps?limit=100"        -H "authorization: Bearer $TOKEN"
statusMeaning
QUEUEDA dry run you asked for that the worker has not started
RUNNINGWorking, or paused on a Wait step until waitingUntil
SUCCESSEvery step did what it was asked
PARTIALIt ran, and some steps were refused or failed: problems says which
FAILEDIt stopped on an error
DRY_RUNA finished dry run: its steps say what would have happened

A run's steps come in the order they ran, each with its node, the record it worked on, what it read and wrote, and, for a condition, its reasoning (conditionTrace). A batch run takes a step per node per car, so page through them with limit and offset.

Events

EventWhenBody
AUTOMATION.PUBLISHEDCypress published a draft you submittedautomationId, automationName, version, publishedAt
AUTOMATION.SENT_BACKCypress sent a submitted draft backautomationId, automationName, version, note, sentBackAt
AUTOMATION.RUN.COMPLETEDA run of one of your automations finished: status is SUCCESS, PARTIAL (some steps were refused or failed: problems says which) or DRY_RUN (a dry run you asked the API for)runId, automationId, automationName, version, status, dryRun, startedBy, subject, vehiclesEvaluated, vehiclesActioned, problems, durationMs, startedAt, completedAt
AUTOMATION.RUN.FAILEDA run stopped on an errorThe same, with the error in problems

Each run is told once, when it is over: a run paused on a Wait step is told when its last wait ends. The href reads the automation or the run back (a run's steps are at stepsHref). Like TASK.*, they are opt-in: only a Cypress-dialect subscription that lists them gets them, subscribing needs automations:read, and nothing is sent while your Automations product is off. Cypress's own automations never send these. A dry run someone at Cypress starts is not sent; one you asked the API for is, so you can wait for it instead of polling.