Transactional — Automation Node¶
Nodes are the steps of an automation. Each node has a type, a
child (the next node, or null when the contact leaves the flow) and, for ifElse and
externalEvent, a child2 (the second branch). A node's settings are kept in payload and are
set with a PUT specific to its type.
Endpoints¶
| Method | URL |
|---|---|
POST |
/transactional/<transactional>/automation/<automation>/node |
PUT |
/transactional/<transactional>/automation/<automation>/node/<node>/<type> |
DELETE |
/transactional/<transactional>/automation/<automation>/node/<node> |
Nodes are read with GET /transactional/<transactional>/automation/<automation>.
Send the parameters form-encoded or in the query string.
Node types¶
| Type | Kind | What it does | Branches |
|---|---|---|---|
contactSignup |
Entry | A contact is added to the list (API, CSV upload, form, or a contact created by an event) | child |
contactAnniversary |
Entry | The date in a custom field of the contact comes round again (checked every hour) | child |
externalEventEntry |
Entry | You call the event URL for the contact | child |
smsReceivedEntry |
Entry | The contact sends an SMS to one of your inbound numbers | child |
existingContact |
Entry | Not processed at the moment. Do not use. | child |
loopingContact |
Entry | Not processed at the moment. Do not use. | child |
sendMessage |
Action | Sends a transactional message (email and/or SMS) | child |
setField |
Action | Sets custom fields of the contact | child |
httpCallback |
Action | Sends an HTTP POST to your service |
child |
wait |
Wait | Waits a fixed period | child |
externalEvent |
Wait | Waits for an event for the contact, with an optional timeout | child = event, child2 = timeout |
smsReceived |
Wait | Waits for an SMS from the contact, with an optional timeout | child (SMS or timeout) |
ifElse |
Condition | Tests fields of the contact | child = true, child2 = false |
POST /transactional/<transactional>/automation/<automation>/node¶
Creates a node and links it into the flow.
| Parameter | Type | Description |
|---|---|---|
type |
string | Required. One of the node types above |
connectFrom |
string | Required. Where to attach the node: null for an entry node; the ID of the parent node (the new node becomes its child); <id>[1] for the second branch (child2) of an ifElse or externalEvent node; or start for the first step after the entry nodes |
connectTo |
string | Required. null to add the node at the end of a branch, or the ID of an existing node to insert the new node before it. In that case, every node that pointed to it now points to the new node. |
title |
string | Optional. Defaults to a label for the type |
comment |
string | Optional. Defaults to a description for the type |
- Entry types (
contactSignup,contactAnniversary,externalEventEntry,smsReceivedEntry) must be created withconnectFrom=null&connectTo=null, and the other types must not. Otherwise the request fails withIncompatible type and position. - A new entry node leads to the same first step as the existing entry nodes.
- To add a node between two nodes, set
connectToto the next node. WithconnectTo=null, attach only to a node or branch that has no next node yet.
Returns: The new node (transactionalAutomationNode) and the automation.
Example — add a sendMessage node after node 31:
curl -u "username:api_key" -H "Accept: application/json" \
-d "type=sendMessage&connectFrom=31&connectTo=null" \
https://app.duo.pt/transactional/{transactional_id}/automation/{automation_id}/node
Response:
{
"success": true,
"data": {
"transactionalAutomation": {
"id": 7,
"name": "Payment follow-up",
"enabled": false,
"send_transactional": 1
},
"transactionalAutomationNode": {
"id": 32,
"send_transactional_automation": 7,
"type": "sendMessage",
"title": "Receives a message",
"comment": "Click to select message",
"child": null,
"child2": null,
"payload": null
}
}
}
PUT /transactional/<transactional>/automation/<automation>/node/<node>/<type>¶
Sets the node's settings. <type> must be the node's type. Send a POST with x-verb=PUT.
Each call replaces the whole payload.
Returns: transactional, transactionalAutomation and the updated
transactionalAutomationNode, with its payload and a new comment.
contactSignup¶
| Parameter | Type | Description |
|---|---|---|
segment |
int | Optional. ID of a segment of the list. Stored, but not applied at the moment: every new contact enters. |
Payload: {"segment": 5}
contactAnniversary¶
| Parameter | Type | Description |
|---|---|---|
anniversary_field |
int | ID of the list's custom field that holds the date |
anniversary_period |
string | Optional. year (default), month, week, day or hour |
Payload: {"field_to_check": 42, "check_period": "year"}
externalEventEntry¶
| Parameter | Type | Description |
|---|---|---|
event |
string | Required. Event name. It is a label: the event URL identifies the node. |
fields_to_set[argument][] |
string array | Required, may be empty. Reserved: stored, but not applied at the moment. |
fields_to_set[custom_field][] |
string array | Required, may be empty. Reserved, same index as argument. |
Payload: {"event": "payment", "fields_to_set": []}
externalEvent¶
The parameters of externalEventEntry, plus:
| Parameter | Type | Description |
|---|---|---|
period |
int | Timeout in seconds. On timeout the contact goes to child2. 0 waits for the event only. |
Set a timeout only when you need the second branch.
wait¶
| Parameter | Type | Description |
|---|---|---|
period |
int | Wait in seconds. Must be greater than 0: with 0 the contact stays in the node. |
Payload: {"period": 86400}
sendMessage¶
| Parameter | Type | Description |
|---|---|---|
message |
int | ID of a message of this transactional object. Other IDs are ignored. |
Payload: {"message": 12}. The contact receives the message's email if it has an email
address, and its SMS if it has a telephone number. Contacts that are not subscribed or are
bouncing receive nothing but continue in the flow.
setField¶
| Parameter | Type | Description |
|---|---|---|
fields_to_set[argument][] |
string array | Required. Values to set |
fields_to_set[custom_field][] |
int array | Required. Custom field IDs of the list, same index as the values |
Payload: {"fields_to_set": {"VIP": "43"}} (value → field ID). Each value can be used once per
node: to write the same value in two fields, use two setField nodes.
ifElse¶
| Parameter | Type | Description |
|---|---|---|
payload[topoperator] |
string | AND (all conditions) or OR (any condition). Any other value means OR. |
payload[condition_field][] |
string array | email, telephone or the ID of a custom field of the list |
payload[condition_operator][] |
string array | ==, !=, contains, !contains, starts_with, !starts_with, ends_with, !ends_with; > and < for numbers; before, after and is_today for dates (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS) |
payload[condition_operand][] |
string array | Value to compare with (empty for is_today) |
Payload: {"topoperator": "AND", "operands": [{"field": "45", "operator": "==", "operand": "yes"}]}.
True → child, false → child2.
Tip
Send only complete conditions, with fields of the transactional object's list, and no empty
rows. For text fields, prefer == and !=. Check every condition with a test contact
before you enable the automation.
httpCallback¶
| Parameter | Type | Description |
|---|---|---|
url |
string | Required. http:// or https:// URL of your service |
parameterName[] |
string array | Names of the body fields |
parameterSource[] |
string array | static (fixed value) or field (value of the contact) |
parameterStaticValue[] |
string array | The value, when the source is static |
parameterFieldValue[] |
string array | email, telephone or a custom field ID, when the source is field |
http_error |
int | Optional. ID of a custom field that receives the HTTP status code. When set, the contact also continues to child after an error. |
http_result |
int | Optional. ID of a custom field that receives the response body |
Send the four parameter…[] arrays with one entry per parameter, using empty values where they
do not apply. A parameter with an empty name is ignored.
Payload: {"url": "https://example.com/duo/hook", "http_error": null, "http_result": 44, "http_parameters": [{"name": "email", "source": "field", "fieldValue": "email"}, {"name": "token", "source": "static", "staticValue": "s3cr3t"}]}
The request DUO makes: POST <url> with Content-Type: application/x-www-form-urlencoded
and the parameters as body fields (no body if there are none), User-Agent: duo/<version>, and
a 60-second timeout. A 2xx answer moves the contact to child. On any other answer, or if the
request fails, the contact does not continue, unless http_error is set. Requests are not
signed and not retried: put a secret token in a static parameter and check it on your side.
Example — configure an httpCallback node:
curl -u "username:api_key" -H "Accept: application/json" \
--data-urlencode "x-verb=PUT" \
--data-urlencode "url=https://example.com/duo/hook" \
--data-urlencode "parameterName[]=email" --data-urlencode "parameterSource[]=field" \
--data-urlencode "parameterStaticValue[]=" --data-urlencode "parameterFieldValue[]=email" \
--data-urlencode "parameterName[]=token" --data-urlencode "parameterSource[]=static" \
--data-urlencode "parameterStaticValue[]=s3cr3t" --data-urlencode "parameterFieldValue[]=" \
--data-urlencode "http_error=" --data-urlencode "http_result=" \
https://app.duo.pt/transactional/{transactional_id}/automation/{automation_id}/node/{node_id}/httpCallback
smsReceivedEntry, smsReceived¶
| Parameter | Type | Description |
|---|---|---|
inbound_telephone |
int | Optional. ID of one of your inbound SMS numbers. Empty for any of them. |
field_to_set |
int | Optional. ID of a custom field that receives the SMS text |
value_regex |
string | Optional. Regular expression with one capture group. The captured text is stored instead of the whole SMS (case-insensitive). |
period |
int | smsReceived only. Timeout in seconds; on timeout the contact also goes to child. 0 waits without a timeout. |
Payload: {"inbound_telephone": null, "set_field": {"field": 45, "source": "regex", "regex": "^YES (\\d+)"}, "timeout": 3600}
DELETE /transactional/<transactional>/automation/<automation>/node/<node>¶
Deletes the node. The nodes that pointed to it now point to its child. Deleting an ifElse
or externalEvent node also deletes the first node of its second branch: delete the nodes of
that branch first, from the last to the first.
Returns: transactional, transactionalAutomation and the deleted
transactionalAutomationNode.
Example: