readyDocs Open the appOpen the app

Build automations

These are the routes behind the app’s automation builder. Every route here needs the manage_campaigns permission unless it says otherwise. Test keys can read, but any change is refused with 403 test_key_not_allowed. To create, change, turn on or off and delete an automation from a plain list of steps, see Automations.

#The flow graph

An automation built on the canvas is saved as a graph: nodes (a trigger node and one node per step, each with an id, a type, its settings and a position), edges ({ "from", "to" } between node ids) and a viewport. Each save turns the graph into the steps the automation runs. The easy way to make a valid graph is to read one with GET /automations/:id/graph and send back a changed copy.

#Get an automation’s graph

The saved graph. An automation that was never saved from the canvas gets a graph laid out from its steps, so every automation has one.

Parameters

idinteger, pathRequired
The automation id.
Returns
data.idinteger
The automation id.
data.namestring
Its name.
data.enabledboolean
Whether it is on.
data.graphobject
nodes, edges and viewport.
Errors
HTTPCodeWhen
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
500GRAPH_UNAVAILABLEIts steps couldn’t be laid out as a graph. Nothing was changed; contact support.

#Save an automation’s graph

Replaces the graph and the steps it runs. The graph it replaces is kept as an earlier version. Leave out enabled to keep it on or off as it is.

Parameters

idinteger, pathRequired
The automation id.
graphobjectRequired
The whole graph: nodes, edges and viewport.
namestring
A new name.
enabledboolean
true turns it on, any other value turns it off. An automation that is off stays off if the graph isn’t finished; blocked_activation says why.
check_empty_mergeboolean
As on Update an automation: when this save turns it on, ask first about merge fields that are blank for some of your newest contacts (confirm_empty_merge: true to go ahead). Also adds empty_merge to the answer.
Returns
dataobject
The saved Automation object, with its graph_json and triggers.
unreachablearray
Steps the trigger can’t reach. Empty when every step is connected.
waiting_contactsinteger
Contacts waiting in this automation right now.
warningstring
Present when some steps are not connected.
blocked_activationstring
Present when you asked to turn it on and it isn’t finished. It was saved, and it is off.
Errors
HTTPCodeWhen
400GRAPH_REQUIREDNo graph.
400GRAPH_INVALIDPart of the graph isn’t set up correctly. Other codes, such as GRAPH_HAS_LOOP, GRAPH_EMPTY, TRIGGER_INVALID or WEBHOOK_URL_INVALID, name the problem; error says what to fix and step_id may name the node.
400NAME_REQUIREDA blank name.
400SHEETS_ACTIVATION_FAILEDA Google Sheets trigger couldn’t be set up.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
500GRAPH_SAVE_FAILEDWe couldn’t save. Retry.

#Create an automation from a graph

Saves a new automation from a graph. It is saved off unless you send enabled: true, and stays off if the graph isn’t finished. Takes an optional Idempotency-Key header: a repeat with the same key returns the first answer.

Parameters

namestringRequired
Up to 180 characters.
graphobjectRequired
nodes, edges and viewport.
enabledboolean
true to save it on.
check_empty_mergeboolean
Adds empty_merge to the answer. It never stops the save.
Returns
dataobject
The new Automation object, with its graph_json and triggers.
Errors
HTTPCodeWhen
400NAME_REQUIREDNo name.
400GRAPH_REQUIREDNo graph.
400GRAPH_INVALIDAs on Save an automation’s graph, with the same other codes.
400SHEETS_ACTIVATION_FAILEDA Google Sheets trigger couldn’t be set up.
500AUTOMATION_CREATE_FAILEDoutcome_unknown: true: it may have been saved. List your automations before you retry.

#Settings

Each automation has its own settings: whether a contact can go through it again, whether a reply stops it, and the hours its texts go out. The number a text goes from is set on each send step.

#Get an automation’s settings

Its saved settings. saved: false means none were ever saved and you are seeing the defaults.

Returns
data.settingsobject
The fields of Update an automation’s settings.
data.savedboolean
Whether these were saved.
Errors
HTTPCodeWhen
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.

#Update an automation’s settings

Send only the fields you change; the rest keep their saved value. A field the automation never saved starts at its default.

Parameters

idinteger, pathRequired
The automation id.
settingsobjectRequired
The fields below.
settings.reentryboolean
Let a contact go through it more than once. Default true.
settings.stop_on_replyboolean
End a contact’s run when they reply. Default false.
settings.windowobject | null
The hours its texts go out: enabled (boolean), tz ("account" or "contact"), start and end (minutes after midnight, 0 to 1440; end after start) and days (0 is Sunday to 6 Saturday; at least one when enabled). Default null: no window of its own.
Returns
dataobject
The saved settings and saved: true.
Errors
HTTPCodeWhen
400SETTINGS_INVALIDA field can’t be used. error says which.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
500SETTINGS_SAVE_FAILEDNothing was changed. Retry.

#Testing

Three ways to check an automation before it goes live, from safest to most real: check the trigger against a sample event, text its messages to your own phone, or run it for real on one contact.

#Check an automation’s trigger

Whether its trigger would start on a sample event. Only the trigger is checked: no condition or step runs, and nothing is sent or saved.

Parameters

idinteger, pathRequired
The automation id.
eventstring
The event name. Leave it out to use the automation’s trigger_type.
dataobject
The sample event’s data, such as { "tag": "hot" } for a Contact tagged trigger. A Manual enrollment trigger never matches.
Returns
matchedboolean
Whether the trigger would start.
ruleobject
The automation: id, name, enabled, trigger_type, trigger_config and actions.
Errors
HTTPCodeWhen
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
500TEST_FAILEDNothing was sent. Retry in a minute.

#Text a preview to yourself

Texts the automation’s first 5 text steps, from every branch except a Wait for reply path or a Loop, to the account owner’s own phone, each starting with [TEST]. Merge fields are filled from the owner’s name, phone and email. No other step runs, and the texts are free. The check that your phone can get texts may be billed as one number lookup, at the price shown under Your price in Settings > Billing. The owner’s phone must be saved and verified in Settings. Before sending we check that phone: if it is opted out, blocked, or in quiet hours, nothing is sent. Each call texts again; send an Idempotency-Key header to make a retry safe.

Parameters

idinteger, pathRequired
The automation id.
Returns
sentinteger
Texts sent.
ofinteger
Text steps found, up to 5. With none, sent is 0 and message says so.
tostring
The owner’s phone. A team member gets recipient: "owner" instead.
blockedstring[]
Why each text that didn’t go out was stopped. Only present when one was.
reply_path_textsinteger
Texts under a Wait for reply path that this test left out. Only present when there are some.
Errors
HTTPCodeWhen
400no_phoneThe owner has no phone number in Settings.
400phone_not_verifiedThe owner’s phone isn’t verified.
400no_active_numberYou have no number that can send.
402BILLING_PAST_DUEThe account is past due.
403PREVIEW_NUMBER_OPTED_OUTThe owner’s phone is opted out of texts from this account.
403PREVIEW_QUIET_HOURSIt is quiet hours for the owner’s phone. Try again later.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
422PREVIEW_NOT_SENTEvery text was stopped. blocked says why.
429rate_limitedToo many sends. Wait and retry.
500TEST_SEND_FAILEDNo texts went out. Retry in a moment.

#Run an automation on one contact

A real run, now, for one contact, whether the automation is on or off. Every step runs: texts go to the contact and cost your per-segment rate, tags are added, and waits are scheduled. The contact’s last text is used as the reply, and AI intent branches take their yes path. Opt-out still applies to every text. In quiet hours a text waits, as in a normal run; see send_now. Check first with GET /automations/:id/test-run/quiet-check. Takes an optional Idempotency-Key header.

Parameters

idinteger, pathRequired
The automation id.
contact_idintegerRequired
The contact to run it on.
send_nowboolean
Send its texts now even outside your own texting days and hours. It lifts only your own texting days and hours, never the legal window for the contact’s area code (8am to 9pm in most states, 8am to 8pm in Florida and Oklahoma, 9am to 8pm in Connecticut) or a contact whose time zone is unknown; texts outside it still wait. We keep this choice, with your IP address and user agent, as your confirmation that the contact agreed to test texts.
Returns
ranobject[]
Each step that ran: type, ok, and skipped, failed or error when it didn’t work.
waitedboolean
true when the run reached a wait. The steps after it run when the wait ends.
stepsinteger
Steps that ran.
failed_stepsinteger
Steps that failed. When any did, warning tells you not to run it again for this contact: the steps that ran already happened.
rule_id, rule_name, contact_id, contact_name
What ran, for whom.
Errors
HTTPCodeWhen
400CONTACT_REQUIREDNo contact_id.
400NO_STEPSIt has no steps.
402BILLING_PAST_DUEThe account is past due.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
404CONTACT_NOT_FOUNDNo contact with this id on your account.
500SEND_NOW_NOT_RECORDEDWe couldn’t record your send_now choice, so nothing ran.
500TEST_RUN_FAILEDNothing ran. Retry in a minute.

#Check quiet hours for a test run

Whether it is quiet hours for a contact right now. Sends nothing.

Parameters

idinteger, pathRequired
The automation id.
contact_idinteger, queryRequired
The contact.
Returns
quietboolean
true in quiet hours.
recipient_tzstring | null
The contact’s time zone.
next_allowed_atISO 8601 string | null
When texting is allowed again.
Errors
HTTPCodeWhen
400CONTACT_REQUIREDNo contact_id.
404CONTACT_NOT_FOUNDNo contact with this id on your account.
500QUIET_CHECK_FAILEDRetry in a minute.

#Test a Filter, Formatter, Math or Loop step

Runs one of these steps on sample values and returns what a real run would compute. No contact, nothing sent or saved.

Parameters

stepobjectRequired
The step, as it is in the automation. Its type is filter, formatter, math or loop.
samplesobject
Sample values, keyed by the name inside each merge field (webhook.price for {{webhook.price}}) or, for a Filter, by each condition’s field. For a Loop, the sample webhook body as a JSON string in __sample_json.
Returns
valueany
Formatter and Math: the result. A Formatter that splits also returns parts.
passedboolean
Filter: whether the sample passes.
count, runs, capped, first_items
Loop: how many items it found, how many it would run, whether that hit the limit, and the first 3 items.
Errors
HTTPCodeWhen
400TOOL_TEST_UNSUPPORTEDThe step isn’t one of the four types.
413TOOL_SAMPLE_TOO_LARGEThe body is over 200,000 characters.
422no codeThe step can’t run on this sample. error says why.
500TOOL_TEST_FAILEDRetry.

#Folders

Folders group automations in the app. Put an automation in one with folder_id on Update an automation.

#List folders

Every folder, by name: id, name, parent_id (null at the top level) and count, the automations in it.

#Create a folder

Returns the new folder in data.

Parameters

namestringRequired
Up to 120 characters; a longer name is cut.
parent_idinteger
Put it inside this folder.
Errors
HTTPCodeWhen
400FOLDER_NAME_REQUIREDNo name.
400FOLDER_PARENT_NOT_FOUNDNo folder with parent_id on your account.
500FOLDER_CREATE_FAILEDRetry in a minute.

#Rename or move a folder

Send a new name, a new parent_id, or both. parent_id: null moves it to the top level. Returns { "success": true }.

Parameters

idinteger, pathRequired
The folder id.
namestring
A new name.
parent_idinteger | null
The folder to move it into.
Errors
HTTPCodeWhen
400FOLDER_UPDATE_EMPTYNeither name nor parent_id.
400FOLDER_PARENT_INVALIDparent_id is the folder itself or not a number.
400FOLDER_PARENT_NOT_FOUNDNo folder with parent_id on your account.
400FOLDER_MOVE_INTO_SELFparent_id is one of its own sub-folders.
404FOLDER_NOT_FOUNDNo folder with this id on your account.
500FOLDER_UPDATE_FAILEDRetry in a minute.

#Delete a folder

Its sub-folders move up into its parent, and its automations are taken out of any folder. No automation is deleted. Returns { "success": true }.

Errors
HTTPCodeWhen
404FOLDER_NOT_FOUNDNo folder with this id on your account.
500FOLDER_DELETE_FAILEDThe folder is still there. Retry.

#Templates

#List templates

Ready’s built-in templates and your own, newest first. To start from one of yours, send its graph to POST /automations/from-graph. A built-in template’s graph is in the app builder’s own draft format, so open it in the app.

Returns
data.builtinobject[]
Each with key, name, description, industries, apps, setup and graph.
data.mineobject[]
Yours, up to 100: id, name, description, created_at and graph.

#Save an automation as a template

Saves a copy of its graph, without the connected app accounts its steps picked. The automation doesn’t change. You can keep up to 100. Returns the template’s id in data.

Parameters

automation_idintegerRequired
The automation to save.
namestringRequired
Up to 200 characters.
descriptionstring
Up to 1,000 characters.
Errors
HTTPCodeWhen
400INVALID_IDautomation_id isn’t a valid id.
400NAME_REQUIREDA blank name.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
409TOO_MANY_TEMPLATESYou already have 100. Delete one first.
413TEMPLATE_TOO_LARGEThe automation is too large to save as a template.
500TEMPLATE_NOT_SAVEDRetry.

#Delete a template

Deletes one of your templates. Automations made from it don’t change. Returns { "success": true }.

Errors
HTTPCodeWhen
404TEMPLATE_NOT_FOUNDNo template with this id on your account.
500TEMPLATE_NOT_DELETEDRetry.

#AI builder

#Draft an automation with AI

Describe what it should do, or attach screenshots of a workflow from another tool, and get back a draft. Nothing is saved: review it, then save it with Create an automation (send enabled: false to keep it off while you check it). If the goal is unclear, the first answer may be up to 2 questions instead; send your choices back in answers. Each call counts against your account’s limit on AI requests per 15 minutes.

Parameters

goalstring
What the automation should do, up to 800 characters. Send this, images, or both.
imagesobject[]
Screenshots as { "data": "<base64>", "media_type": "image/png" } (PNG, JPEG, GIF or WebP). The first 6 are used. With a screenshot we build without asking questions.
answersobject
Your answers to its questions, keyed by each question’s key.
currentobject
An existing draft or automation to change (name, trigger_type, trigger_config, actions), up to 2,000 characters as JSON. The answer is the whole changed automation.
Returns
dataobject
Either { "clarify": true, "questions": [...] }, each question with key, question, options and multi; or a draft: name, trigger_type, trigger_config, actions and explanation. A draft may add dropped_count and dropped_types for steps it couldn’t build, and, from a screenshot whose trigger we don’t have, an empty trigger_type with the screenshot’s words in trigger_unmatched.
Errors
HTTPCodeWhen
400GOAL_REQUIREDNo goal and no usable image.
400GOAL_TOO_LONGgoal is over 800 characters.
400RULE_TOO_LARGE_FOR_AI_EDITcurrent is too long to change safely.
413IMAGES_TOO_LARGEThe screenshots are too large together.
429rate_limitedToo many AI requests. Wait a few minutes.
502AI_BAD_RESPONSEThe AI’s answer couldn’t be used. Try again or reword it.
503AI_UNAVAILABLEThe AI builder isn’t available right now.
503AI_BUDGET_PAUSEDThe AI builder is paused for now. Build it step by step.
500AI_GENERATION_FAILEDTry again.

#Earlier versions

Each canvas save that changes an automation’s graph first keeps the graph it replaces, and each drip campaign steps save keeps the steps it replaces. You can put one back. A restore is a save too, so it can be undone the same way.

#List earlier versions

The 50 newest versions of one automation or drip campaign, newest first. For an automation, needs the manage_campaigns permission.

Parameters

kindstring, queryRequired
rule for an automation, drip for a drip campaign.
target_idinteger, queryRequired
The automation or drip campaign id.
Returns
dataobject[]
Each with id, created_at, step_count and reason, the save that replaced it: graph_save, steps_save or version_restore.
Errors
HTTPCodeWhen
400VERSION_TARGET_INVALIDA bad kind or target_id.
404AUTOMATION_NOT_FOUNDNo automation with this id on your account.
404DRIP_NOT_FOUNDNo drip campaign with this id on your account (kind=drip).
500VERSIONS_LOAD_FAILEDRetry.

#Restore an earlier version

Puts that version back through the same save the builder uses, with the same checks. An automation stays on or off as it is. Needs the send_sms permission, and for an automation manage_campaigns as well. An automation answers as Save an automation’s graph does, plus the restored graph; a drip campaign answers as its steps save does. Both add kind and target_id.

Parameters

idinteger, pathRequired
The version id from the list.
Errors
HTTPCodeWhen
400no codeA drip campaign version with no steps.
404VERSION_NOT_FOUNDNo version with this id on your account.
404AUTOMATION_NOT_FOUNDThe automation was deleted.
404DRIP_NOT_FOUNDThe drip campaign was deleted (kind=drip).
500VERSION_RESTORE_FAILEDNothing was changed. Retry in a minute.
500VERSION_RESTORE_UNCONFIRMEDWe couldn’t confirm it was restored. Read it again before you retry.