loops_sdk 2.3.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1781 -70
- data/lib/loops_sdk/audience_segments.rb +5 -0
- data/lib/loops_sdk/base.rb +3 -1
- data/lib/loops_sdk/campaigns.rb +4 -0
- data/lib/loops_sdk/components.rb +9 -0
- data/lib/loops_sdk/email_messages.rb +5 -0
- data/lib/loops_sdk/event_patterns.rb +22 -0
- data/lib/loops_sdk/themes.rb +10 -0
- data/lib/loops_sdk/transactional.rb +4 -0
- data/lib/loops_sdk/version.rb +1 -1
- data/lib/loops_sdk/workflow_groups.rb +25 -0
- data/lib/loops_sdk/workflows.rb +135 -0
- data/lib/loops_sdk.rb +2 -0
- metadata +4 -2
data/README.md
CHANGED
|
@@ -120,28 +120,54 @@ You can use custom contact properties in API calls. Please make sure to [add cus
|
|
|
120
120
|
- [Transactional.update()](#transactionalupdate)
|
|
121
121
|
- [Transactional.ensure_draft()](#transactionalensure_draft)
|
|
122
122
|
- [Transactional.publish()](#transactionalpublish)
|
|
123
|
+
- [Transactional.metrics()](#transactionalmetrics)
|
|
123
124
|
- [Transactional.send()](#transactionalsend)
|
|
124
125
|
- [DedicatedSendingIps.list()](#dedicatedsendingipslist)
|
|
125
126
|
- [Themes.list()](#themeslist)
|
|
126
127
|
- [Themes.get()](#themesget)
|
|
128
|
+
- [Themes.create()](#themescreate)
|
|
129
|
+
- [Themes.update()](#themesupdate)
|
|
127
130
|
- [Components.list()](#componentslist)
|
|
128
131
|
- [Components.get()](#componentsget)
|
|
132
|
+
- [Components.create()](#componentscreate)
|
|
133
|
+
- [Components.update()](#componentsupdate)
|
|
129
134
|
- [Campaigns.list()](#campaignslist)
|
|
130
135
|
- [Campaigns.create()](#campaignscreate)
|
|
131
136
|
- [Campaigns.get()](#campaignsget)
|
|
132
137
|
- [Campaigns.update()](#campaignsupdate)
|
|
138
|
+
- [Campaigns.metrics()](#campaignsmetrics)
|
|
133
139
|
- [CampaignGroups.list()](#campaigngroupslist)
|
|
134
140
|
- [CampaignGroups.create()](#campaigngroupscreate)
|
|
135
141
|
- [CampaignGroups.get()](#campaigngroupsget)
|
|
136
142
|
- [CampaignGroups.update()](#campaigngroupsupdate)
|
|
143
|
+
- [WorkflowGroups.list()](#workflowgroupslist)
|
|
144
|
+
- [WorkflowGroups.create()](#workflowgroupscreate)
|
|
145
|
+
- [WorkflowGroups.get()](#workflowgroupsget)
|
|
146
|
+
- [WorkflowGroups.update()](#workflowgroupsupdate)
|
|
137
147
|
- [AudienceSegments.list()](#audiencesegmentslist)
|
|
138
148
|
- [AudienceSegments.get()](#audiencesegmentsget)
|
|
149
|
+
- [AudienceSegments.create()](#audiencesegmentscreate)
|
|
139
150
|
- [Workflows.list()](#workflowslist)
|
|
151
|
+
- [Workflows.create()](#workflowscreate)
|
|
140
152
|
- [Workflows.get()](#workflowsget)
|
|
153
|
+
- [Workflows.update()](#workflowsupdate)
|
|
154
|
+
- [Workflows.delete()](#workflowsdelete)
|
|
155
|
+
- [Workflows.change_mailing_list()](#workflowschange_mailing_list)
|
|
141
156
|
- [Workflows.get_node()](#workflowsget_node)
|
|
157
|
+
- [Workflows.get_node_metrics()](#workflowsget_node_metrics)
|
|
158
|
+
- [Workflows.create_node()](#workflowscreate_node)
|
|
159
|
+
- [Workflows.update_node()](#workflowsupdate_node)
|
|
160
|
+
- [Workflows.delete_node()](#workflowsdelete_node)
|
|
161
|
+
- [Workflows.add_branch()](#workflowsadd_branch)
|
|
162
|
+
- [Workflows.reroute_node()](#workflowsreroute_node)
|
|
163
|
+
- [Workflows.delete_node_recursive()](#workflowsdelete_node_recursive)
|
|
164
|
+
- [EventPatterns.list()](#eventpatternslist)
|
|
165
|
+
- [EventPatterns.get()](#eventpatternsget)
|
|
166
|
+
- [EventPatterns.get_by_name()](#eventpatternsget_by_name)
|
|
142
167
|
- [EmailMessages.get()](#emailmessagesget)
|
|
143
168
|
- [EmailMessages.update()](#emailmessagesupdate)
|
|
144
169
|
- [EmailMessages.preview()](#emailmessagespreview)
|
|
170
|
+
- [EmailMessages.run_guardian()](#emailmessagesrun_guardian)
|
|
145
171
|
- [TransactionalGroups.list()](#transactionalgroupslist)
|
|
146
172
|
- [TransactionalGroups.create()](#transactionalgroupscreate)
|
|
147
173
|
- [TransactionalGroups.get()](#transactionalgroupsget)
|
|
@@ -851,6 +877,21 @@ Get a single transactional email by ID.
|
|
|
851
877
|
response = LoopsSdk::Transactional.get(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
852
878
|
```
|
|
853
879
|
|
|
880
|
+
#### Response
|
|
881
|
+
|
|
882
|
+
```json
|
|
883
|
+
{
|
|
884
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
885
|
+
"name": "Sign up confirmation",
|
|
886
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
887
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
888
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
889
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
890
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
891
|
+
"dataVariables": ["confirmationUrl"]
|
|
892
|
+
}
|
|
893
|
+
```
|
|
894
|
+
|
|
854
895
|
---
|
|
855
896
|
|
|
856
897
|
### Transactional.update()
|
|
@@ -878,6 +919,21 @@ response = LoopsSdk::Transactional.update(
|
|
|
878
919
|
)
|
|
879
920
|
```
|
|
880
921
|
|
|
922
|
+
#### Response
|
|
923
|
+
|
|
924
|
+
```json
|
|
925
|
+
{
|
|
926
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
927
|
+
"name": "Updated name",
|
|
928
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
929
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
930
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
931
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
932
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
933
|
+
"dataVariables": ["confirmationUrl"]
|
|
934
|
+
}
|
|
935
|
+
```
|
|
936
|
+
|
|
881
937
|
---
|
|
882
938
|
|
|
883
939
|
### Transactional.ensure_draft()
|
|
@@ -898,6 +954,22 @@ Ensure a transactional email has a draft email message. If a draft already exist
|
|
|
898
954
|
response = LoopsSdk::Transactional.ensure_draft(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
899
955
|
```
|
|
900
956
|
|
|
957
|
+
#### Response
|
|
958
|
+
|
|
959
|
+
```json
|
|
960
|
+
{
|
|
961
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
962
|
+
"name": "Sign up confirmation",
|
|
963
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
964
|
+
"draftEmailMessageContentRevisionId": "clrev1s10n2i3d4e5f6g7h8",
|
|
965
|
+
"publishedEmailMessageId": null,
|
|
966
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
967
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
968
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
969
|
+
"dataVariables": []
|
|
970
|
+
}
|
|
971
|
+
```
|
|
972
|
+
|
|
901
973
|
---
|
|
902
974
|
|
|
903
975
|
### Transactional.publish()
|
|
@@ -918,6 +990,53 @@ Publish a transactional email's current draft. The draft becomes the published v
|
|
|
918
990
|
response = LoopsSdk::Transactional.publish(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
919
991
|
```
|
|
920
992
|
|
|
993
|
+
#### Response
|
|
994
|
+
|
|
995
|
+
```json
|
|
996
|
+
{
|
|
997
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
998
|
+
"name": "Sign up confirmation",
|
|
999
|
+
"draftEmailMessageId": null,
|
|
1000
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
1001
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1002
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1003
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
1004
|
+
"dataVariables": []
|
|
1005
|
+
}
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
### Transactional.metrics()
|
|
1011
|
+
|
|
1012
|
+
Get all-time delivery metrics for a transactional email.
|
|
1013
|
+
|
|
1014
|
+
[API Reference](https://loops.so/docs/api-reference/get-transactional-email-metrics)
|
|
1015
|
+
|
|
1016
|
+
#### Parameters
|
|
1017
|
+
|
|
1018
|
+
| Name | Type | Required | Notes |
|
|
1019
|
+
| ------------------ | ------ | -------- | ----- |
|
|
1020
|
+
| `transactional_id` | string | Yes | |
|
|
1021
|
+
|
|
1022
|
+
#### Example
|
|
1023
|
+
|
|
1024
|
+
```ruby
|
|
1025
|
+
response = LoopsSdk::Transactional.metrics(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
#### Response
|
|
1029
|
+
|
|
1030
|
+
```json
|
|
1031
|
+
{
|
|
1032
|
+
"sends": 4210,
|
|
1033
|
+
"deliveries": 4175,
|
|
1034
|
+
"spamReports": 1,
|
|
1035
|
+
"hardBounces": 9,
|
|
1036
|
+
"softBounces": 13
|
|
1037
|
+
}
|
|
1038
|
+
```
|
|
1039
|
+
|
|
921
1040
|
---
|
|
922
1041
|
|
|
923
1042
|
### Transactional.send()
|
|
@@ -1060,6 +1179,31 @@ response = LoopsSdk::Themes.list
|
|
|
1060
1179
|
response = LoopsSdk::Themes.list(perPage: 15, cursor: "cursor_value")
|
|
1061
1180
|
```
|
|
1062
1181
|
|
|
1182
|
+
#### Response
|
|
1183
|
+
|
|
1184
|
+
```json
|
|
1185
|
+
{
|
|
1186
|
+
"pagination": {
|
|
1187
|
+
"totalResults": 1,
|
|
1188
|
+
"returnedResults": 1,
|
|
1189
|
+
"perPage": 20,
|
|
1190
|
+
"totalPages": 1,
|
|
1191
|
+
"nextCursor": null,
|
|
1192
|
+
"nextPage": null
|
|
1193
|
+
},
|
|
1194
|
+
"data": [
|
|
1195
|
+
{
|
|
1196
|
+
"id": "clo1z5q7s004yl70y3z4a5b6c",
|
|
1197
|
+
"name": "Default",
|
|
1198
|
+
"styles": { "backgroundColor": "#ffffff" },
|
|
1199
|
+
"isDefault": true,
|
|
1200
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1201
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1202
|
+
}
|
|
1203
|
+
]
|
|
1204
|
+
}
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1063
1207
|
---
|
|
1064
1208
|
|
|
1065
1209
|
### Themes.get()
|
|
@@ -1080,6 +1224,100 @@ Get a single theme by ID.
|
|
|
1080
1224
|
response = LoopsSdk::Themes.get(theme_id: "clo5p8q0r0132ntx6flkunw89")
|
|
1081
1225
|
```
|
|
1082
1226
|
|
|
1227
|
+
#### Response
|
|
1228
|
+
|
|
1229
|
+
```json
|
|
1230
|
+
{
|
|
1231
|
+
"id": "clo1z5q7s004yl70y3z4a5b6c",
|
|
1232
|
+
"name": "Default",
|
|
1233
|
+
"styles": { "backgroundColor": "#ffffff" },
|
|
1234
|
+
"isDefault": true,
|
|
1235
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1236
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1237
|
+
}
|
|
1238
|
+
```
|
|
1239
|
+
|
|
1240
|
+
---
|
|
1241
|
+
|
|
1242
|
+
### Themes.create()
|
|
1243
|
+
|
|
1244
|
+
Create a new email theme.
|
|
1245
|
+
|
|
1246
|
+
[API Reference](https://loops.so/docs/api-reference/create-theme)
|
|
1247
|
+
|
|
1248
|
+
#### Parameters
|
|
1249
|
+
|
|
1250
|
+
| Name | Type | Required | Notes |
|
|
1251
|
+
| -------- | ------ | -------- | -------------------------------------------------------------------------------------------------- |
|
|
1252
|
+
| `name` | string | Yes | |
|
|
1253
|
+
| `styles` | object | No | Style attributes matching LMX `<Style />` tag attribute names. See the API reference for the full list. |
|
|
1254
|
+
|
|
1255
|
+
#### Example
|
|
1256
|
+
|
|
1257
|
+
```ruby
|
|
1258
|
+
response = LoopsSdk::Themes.create(
|
|
1259
|
+
name: "Dark mode",
|
|
1260
|
+
styles: { backgroundColor: "#111827", bodyColor: "#1f2937" }
|
|
1261
|
+
)
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
#### Response
|
|
1265
|
+
|
|
1266
|
+
```json
|
|
1267
|
+
{
|
|
1268
|
+
"id": "clt3u5v7w9x1y3z5a7b9c1d3",
|
|
1269
|
+
"name": "Dark mode",
|
|
1270
|
+
"styles": {
|
|
1271
|
+
"backgroundColor": "#111827",
|
|
1272
|
+
"bodyColor": "#1f2937"
|
|
1273
|
+
},
|
|
1274
|
+
"isDefault": false,
|
|
1275
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1276
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1277
|
+
}
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
---
|
|
1281
|
+
|
|
1282
|
+
### Themes.update()
|
|
1283
|
+
|
|
1284
|
+
Update a theme's name and/or styles. Style changes cascade to emails using the theme.
|
|
1285
|
+
|
|
1286
|
+
[API Reference](https://loops.so/docs/api-reference/update-theme)
|
|
1287
|
+
|
|
1288
|
+
#### Parameters
|
|
1289
|
+
|
|
1290
|
+
| Name | Type | Required | Notes |
|
|
1291
|
+
| ---------- | ------ | -------- | ----- |
|
|
1292
|
+
| `theme_id` | string | Yes | |
|
|
1293
|
+
| `name` | string | No | |
|
|
1294
|
+
| `styles` | object | No | |
|
|
1295
|
+
|
|
1296
|
+
At least one of `name` or `styles` must be provided.
|
|
1297
|
+
|
|
1298
|
+
#### Example
|
|
1299
|
+
|
|
1300
|
+
```ruby
|
|
1301
|
+
response = LoopsSdk::Themes.update(
|
|
1302
|
+
theme_id: "clo5p8q0r0132ntx6flkunw89",
|
|
1303
|
+
name: "Updated theme"
|
|
1304
|
+
)
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
#### Response
|
|
1308
|
+
|
|
1309
|
+
```json
|
|
1310
|
+
{
|
|
1311
|
+
"id": "clt3u5v7w9x1y3z5a7b9c1d3",
|
|
1312
|
+
"name": "Updated theme",
|
|
1313
|
+
"styles": { "backgroundColor": "#111827" },
|
|
1314
|
+
"isDefault": false,
|
|
1315
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1316
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
1317
|
+
"affectedEmailCount": 3
|
|
1318
|
+
}
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1083
1321
|
---
|
|
1084
1322
|
|
|
1085
1323
|
### Components.list()
|
|
@@ -1101,6 +1339,28 @@ List email components.
|
|
|
1101
1339
|
response = LoopsSdk::Components.list
|
|
1102
1340
|
```
|
|
1103
1341
|
|
|
1342
|
+
#### Response
|
|
1343
|
+
|
|
1344
|
+
```json
|
|
1345
|
+
{
|
|
1346
|
+
"pagination": {
|
|
1347
|
+
"totalResults": 1,
|
|
1348
|
+
"returnedResults": 1,
|
|
1349
|
+
"perPage": 20,
|
|
1350
|
+
"totalPages": 1,
|
|
1351
|
+
"nextCursor": null,
|
|
1352
|
+
"nextPage": null
|
|
1353
|
+
},
|
|
1354
|
+
"data": [
|
|
1355
|
+
{
|
|
1356
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1357
|
+
"name": "Header",
|
|
1358
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1359
|
+
}
|
|
1360
|
+
]
|
|
1361
|
+
}
|
|
1362
|
+
```
|
|
1363
|
+
|
|
1104
1364
|
---
|
|
1105
1365
|
|
|
1106
1366
|
### Components.get()
|
|
@@ -1121,6 +1381,88 @@ Get a single component by ID.
|
|
|
1121
1381
|
response = LoopsSdk::Components.get(component_id: "clp6q9r1s0154ouy7gmlovx90")
|
|
1122
1382
|
```
|
|
1123
1383
|
|
|
1384
|
+
#### Response
|
|
1385
|
+
|
|
1386
|
+
```json
|
|
1387
|
+
{
|
|
1388
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1389
|
+
"name": "Header",
|
|
1390
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1391
|
+
}
|
|
1392
|
+
```
|
|
1393
|
+
|
|
1394
|
+
---
|
|
1395
|
+
|
|
1396
|
+
### Components.create()
|
|
1397
|
+
|
|
1398
|
+
Create a new email component from an LMX body.
|
|
1399
|
+
|
|
1400
|
+
[API Reference](https://loops.so/docs/api-reference/create-component)
|
|
1401
|
+
|
|
1402
|
+
#### Parameters
|
|
1403
|
+
|
|
1404
|
+
| Name | Type | Required | Notes |
|
|
1405
|
+
| ------ | ------ | -------- | -------------------------------- |
|
|
1406
|
+
| `name` | string | Yes | |
|
|
1407
|
+
| `lmx` | string | Yes | The component body as LMX. |
|
|
1408
|
+
|
|
1409
|
+
#### Example
|
|
1410
|
+
|
|
1411
|
+
```ruby
|
|
1412
|
+
response = LoopsSdk::Components.create(
|
|
1413
|
+
name: "Header",
|
|
1414
|
+
lmx: "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1415
|
+
)
|
|
1416
|
+
```
|
|
1417
|
+
|
|
1418
|
+
#### Response
|
|
1419
|
+
|
|
1420
|
+
```json
|
|
1421
|
+
{
|
|
1422
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1423
|
+
"name": "Header",
|
|
1424
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1425
|
+
}
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
---
|
|
1429
|
+
|
|
1430
|
+
### Components.update()
|
|
1431
|
+
|
|
1432
|
+
Update a component's name and/or LMX body. Body changes cascade to emails using the component.
|
|
1433
|
+
|
|
1434
|
+
[API Reference](https://loops.so/docs/api-reference/update-component)
|
|
1435
|
+
|
|
1436
|
+
#### Parameters
|
|
1437
|
+
|
|
1438
|
+
| Name | Type | Required | Notes |
|
|
1439
|
+
| -------------- | ------ | -------- | ----- |
|
|
1440
|
+
| `component_id` | string | Yes | |
|
|
1441
|
+
| `name` | string | No | |
|
|
1442
|
+
| `lmx` | string | No | |
|
|
1443
|
+
|
|
1444
|
+
At least one of `name` or `lmx` must be provided.
|
|
1445
|
+
|
|
1446
|
+
#### Example
|
|
1447
|
+
|
|
1448
|
+
```ruby
|
|
1449
|
+
response = LoopsSdk::Components.update(
|
|
1450
|
+
component_id: "clp6q9r1s0154ouy7gmlovx90",
|
|
1451
|
+
name: "Updated Header"
|
|
1452
|
+
)
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
#### Response
|
|
1456
|
+
|
|
1457
|
+
```json
|
|
1458
|
+
{
|
|
1459
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1460
|
+
"name": "Updated Header",
|
|
1461
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>",
|
|
1462
|
+
"affectedEmailCount": 2
|
|
1463
|
+
}
|
|
1464
|
+
```
|
|
1465
|
+
|
|
1124
1466
|
---
|
|
1125
1467
|
|
|
1126
1468
|
### Campaigns.list()
|
|
@@ -1142,6 +1484,36 @@ List campaigns.
|
|
|
1142
1484
|
response = LoopsSdk::Campaigns.list
|
|
1143
1485
|
```
|
|
1144
1486
|
|
|
1487
|
+
#### Response
|
|
1488
|
+
|
|
1489
|
+
```json
|
|
1490
|
+
{
|
|
1491
|
+
"pagination": {
|
|
1492
|
+
"totalResults": 1,
|
|
1493
|
+
"returnedResults": 1,
|
|
1494
|
+
"perPage": 20,
|
|
1495
|
+
"totalPages": 1,
|
|
1496
|
+
"nextCursor": null,
|
|
1497
|
+
"nextPage": null
|
|
1498
|
+
},
|
|
1499
|
+
"data": [
|
|
1500
|
+
{
|
|
1501
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1502
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1503
|
+
"name": "Spring announcement",
|
|
1504
|
+
"status": "Draft",
|
|
1505
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1506
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1507
|
+
"campaignGroupId": null,
|
|
1508
|
+
"mailingListId": null,
|
|
1509
|
+
"audienceSegmentId": null,
|
|
1510
|
+
"audienceFilter": null,
|
|
1511
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1512
|
+
}
|
|
1513
|
+
]
|
|
1514
|
+
}
|
|
1515
|
+
```
|
|
1516
|
+
|
|
1145
1517
|
---
|
|
1146
1518
|
|
|
1147
1519
|
### Campaigns.create()
|
|
@@ -1173,6 +1545,25 @@ response = LoopsSdk::Campaigns.create(
|
|
|
1173
1545
|
)
|
|
1174
1546
|
```
|
|
1175
1547
|
|
|
1548
|
+
#### Response
|
|
1549
|
+
|
|
1550
|
+
```json
|
|
1551
|
+
{
|
|
1552
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1553
|
+
"name": "Spring announcement",
|
|
1554
|
+
"status": "Draft",
|
|
1555
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1556
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1557
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1558
|
+
"emailMessageContentRevisionId": "clv8g2x4z012yl70n5o6p7q8r",
|
|
1559
|
+
"campaignGroupId": null,
|
|
1560
|
+
"mailingListId": null,
|
|
1561
|
+
"audienceSegmentId": null,
|
|
1562
|
+
"audienceFilter": null,
|
|
1563
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1564
|
+
}
|
|
1565
|
+
```
|
|
1566
|
+
|
|
1176
1567
|
---
|
|
1177
1568
|
|
|
1178
1569
|
### Campaigns.get()
|
|
@@ -1193,6 +1584,24 @@ Get a single campaign by ID.
|
|
|
1193
1584
|
response = LoopsSdk::Campaigns.get(campaign_id: "cln4o7p9q0110msw5ekjtmv78")
|
|
1194
1585
|
```
|
|
1195
1586
|
|
|
1587
|
+
#### Response
|
|
1588
|
+
|
|
1589
|
+
```json
|
|
1590
|
+
{
|
|
1591
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1592
|
+
"name": "Spring announcement",
|
|
1593
|
+
"status": "Draft",
|
|
1594
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1595
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1596
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1597
|
+
"campaignGroupId": null,
|
|
1598
|
+
"mailingListId": null,
|
|
1599
|
+
"audienceSegmentId": null,
|
|
1600
|
+
"audienceFilter": null,
|
|
1601
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1602
|
+
}
|
|
1603
|
+
```
|
|
1604
|
+
|
|
1196
1605
|
---
|
|
1197
1606
|
|
|
1198
1607
|
### Campaigns.update()
|
|
@@ -1224,6 +1633,58 @@ response = LoopsSdk::Campaigns.update(
|
|
|
1224
1633
|
)
|
|
1225
1634
|
```
|
|
1226
1635
|
|
|
1636
|
+
#### Response
|
|
1637
|
+
|
|
1638
|
+
```json
|
|
1639
|
+
{
|
|
1640
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1641
|
+
"name": "Updated campaign name",
|
|
1642
|
+
"status": "Draft",
|
|
1643
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1644
|
+
"updatedAt": "2025-01-02T00:00:00.000Z",
|
|
1645
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1646
|
+
"campaignGroupId": null,
|
|
1647
|
+
"mailingListId": null,
|
|
1648
|
+
"audienceSegmentId": null,
|
|
1649
|
+
"audienceFilter": null,
|
|
1650
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1651
|
+
}
|
|
1652
|
+
```
|
|
1653
|
+
|
|
1654
|
+
---
|
|
1655
|
+
|
|
1656
|
+
### Campaigns.metrics()
|
|
1657
|
+
|
|
1658
|
+
Get all-time engagement metrics for a campaign.
|
|
1659
|
+
|
|
1660
|
+
[API Reference](https://loops.so/docs/api-reference/get-campaign-metrics)
|
|
1661
|
+
|
|
1662
|
+
#### Parameters
|
|
1663
|
+
|
|
1664
|
+
| Name | Type | Required | Notes |
|
|
1665
|
+
| ------------- | ------ | -------- | ----- |
|
|
1666
|
+
| `campaign_id` | string | Yes | |
|
|
1667
|
+
|
|
1668
|
+
#### Example
|
|
1669
|
+
|
|
1670
|
+
```ruby
|
|
1671
|
+
response = LoopsSdk::Campaigns.metrics(campaign_id: "cln4o7p9q0110msw5ekjtmv78")
|
|
1672
|
+
```
|
|
1673
|
+
|
|
1674
|
+
#### Response
|
|
1675
|
+
|
|
1676
|
+
```json
|
|
1677
|
+
{
|
|
1678
|
+
"sends": 4210,
|
|
1679
|
+
"opens": 1922,
|
|
1680
|
+
"clicks": 301,
|
|
1681
|
+
"unsubscribes": 12,
|
|
1682
|
+
"spamReports": 1,
|
|
1683
|
+
"hardBounces": 9,
|
|
1684
|
+
"softBounces": 13
|
|
1685
|
+
}
|
|
1686
|
+
```
|
|
1687
|
+
|
|
1227
1688
|
---
|
|
1228
1689
|
|
|
1229
1690
|
### EmailMessages.get()
|
|
@@ -1244,6 +1705,24 @@ Get an email message, including its LMX content.
|
|
|
1244
1705
|
response = LoopsSdk::EmailMessages.get(email_message_id: "cly8k3m0n0044jpx2bghepq45")
|
|
1245
1706
|
```
|
|
1246
1707
|
|
|
1708
|
+
#### Response
|
|
1709
|
+
|
|
1710
|
+
```json
|
|
1711
|
+
{
|
|
1712
|
+
"id": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1713
|
+
"campaignId": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1714
|
+
"subject": "Hello",
|
|
1715
|
+
"previewText": "Preview text",
|
|
1716
|
+
"fromName": "Loops",
|
|
1717
|
+
"fromEmail": "hello",
|
|
1718
|
+
"replyToEmail": "",
|
|
1719
|
+
"emailFormat": "styled",
|
|
1720
|
+
"lmx": "<H1>...</H1><Paragraph>...</Paragraph>",
|
|
1721
|
+
"contentRevisionId": "clv8g2x4z012yl70n5o6p7q8r",
|
|
1722
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1723
|
+
}
|
|
1724
|
+
```
|
|
1725
|
+
|
|
1247
1726
|
---
|
|
1248
1727
|
|
|
1249
1728
|
### EmailMessages.update()
|
|
@@ -1282,15 +1761,33 @@ response = LoopsSdk::EmailMessages.update(
|
|
|
1282
1761
|
preview_text: "See what's new",
|
|
1283
1762
|
from_name: "Loops",
|
|
1284
1763
|
from_email: "hello",
|
|
1285
|
-
lmx: "<
|
|
1764
|
+
lmx: "<Style /><Paragraph>...</Paragraph>"
|
|
1286
1765
|
)
|
|
1287
1766
|
```
|
|
1288
1767
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1768
|
+
#### Response
|
|
1769
|
+
|
|
1770
|
+
```json
|
|
1771
|
+
{
|
|
1772
|
+
"id": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1773
|
+
"campaignId": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1774
|
+
"subject": "Spring announcement",
|
|
1775
|
+
"previewText": "See what's new",
|
|
1776
|
+
"fromName": "Loops",
|
|
1777
|
+
"fromEmail": "hello",
|
|
1778
|
+
"replyToEmail": "",
|
|
1779
|
+
"emailFormat": "styled",
|
|
1780
|
+
"lmx": "<Style /><Paragraph>...</Paragraph>",
|
|
1781
|
+
"contentRevisionId": "clv8g2x4z013yl70s9t0u1v2w",
|
|
1782
|
+
"updatedAt": "2025-01-02T00:00:00.000Z"
|
|
1783
|
+
}
|
|
1784
|
+
```
|
|
1785
|
+
|
|
1786
|
+
---
|
|
1787
|
+
|
|
1788
|
+
### EmailMessages.preview()
|
|
1789
|
+
|
|
1790
|
+
Send a test preview of an email message to one or more addresses.
|
|
1294
1791
|
|
|
1295
1792
|
[API Reference](https://loops.so/docs/api-reference/preview-email-message)
|
|
1296
1793
|
|
|
@@ -1314,6 +1811,50 @@ response = LoopsSdk::EmailMessages.preview(
|
|
|
1314
1811
|
)
|
|
1315
1812
|
```
|
|
1316
1813
|
|
|
1814
|
+
#### Response
|
|
1815
|
+
|
|
1816
|
+
```json
|
|
1817
|
+
{
|
|
1818
|
+
"id": "cle5f7g9h1i3j5k7l9m1n3p5"
|
|
1819
|
+
}
|
|
1820
|
+
```
|
|
1821
|
+
|
|
1822
|
+
---
|
|
1823
|
+
|
|
1824
|
+
### EmailMessages.run_guardian()
|
|
1825
|
+
|
|
1826
|
+
Run Guardian content validation on an email message and return errors and warnings.
|
|
1827
|
+
|
|
1828
|
+
[API Reference](https://loops.so/docs/api-reference/run-guardian-checks)
|
|
1829
|
+
|
|
1830
|
+
#### Parameters
|
|
1831
|
+
|
|
1832
|
+
| Name | Type | Required | Notes |
|
|
1833
|
+
| ------------------ | ------ | -------- | ----- |
|
|
1834
|
+
| `email_message_id` | string | Yes | |
|
|
1835
|
+
|
|
1836
|
+
#### Example
|
|
1837
|
+
|
|
1838
|
+
```ruby
|
|
1839
|
+
response = LoopsSdk::EmailMessages.run_guardian(email_message_id: "cly8k3m0n0044jpx2bghepq45")
|
|
1840
|
+
```
|
|
1841
|
+
|
|
1842
|
+
#### Response
|
|
1843
|
+
|
|
1844
|
+
```json
|
|
1845
|
+
{
|
|
1846
|
+
"errors": [
|
|
1847
|
+
{
|
|
1848
|
+
"rule": "missingButtonHrefs",
|
|
1849
|
+
"title": "Missing button link",
|
|
1850
|
+
"description": "Buttons won't work without href value",
|
|
1851
|
+
"items": [{ "label": "Click here" }]
|
|
1852
|
+
}
|
|
1853
|
+
],
|
|
1854
|
+
"warnings": []
|
|
1855
|
+
}
|
|
1856
|
+
```
|
|
1857
|
+
|
|
1317
1858
|
---
|
|
1318
1859
|
|
|
1319
1860
|
### CampaignGroups.list()
|
|
@@ -1335,6 +1876,30 @@ List campaign groups.
|
|
|
1335
1876
|
response = LoopsSdk::CampaignGroups.list
|
|
1336
1877
|
```
|
|
1337
1878
|
|
|
1879
|
+
#### Response
|
|
1880
|
+
|
|
1881
|
+
```json
|
|
1882
|
+
{
|
|
1883
|
+
"pagination": {
|
|
1884
|
+
"totalResults": 1,
|
|
1885
|
+
"returnedResults": 1,
|
|
1886
|
+
"perPage": 20,
|
|
1887
|
+
"totalPages": 1,
|
|
1888
|
+
"nextCursor": null,
|
|
1889
|
+
"nextPage": null
|
|
1890
|
+
},
|
|
1891
|
+
"data": [
|
|
1892
|
+
{
|
|
1893
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1894
|
+
"name": "Newsletters",
|
|
1895
|
+
"description": "Monthly product updates",
|
|
1896
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1897
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1898
|
+
}
|
|
1899
|
+
]
|
|
1900
|
+
}
|
|
1901
|
+
```
|
|
1902
|
+
|
|
1338
1903
|
---
|
|
1339
1904
|
|
|
1340
1905
|
### CampaignGroups.create()
|
|
@@ -1356,6 +1921,18 @@ Create a campaign group.
|
|
|
1356
1921
|
response = LoopsSdk::CampaignGroups.create(name: "Newsletters", description: "Monthly updates")
|
|
1357
1922
|
```
|
|
1358
1923
|
|
|
1924
|
+
#### Response
|
|
1925
|
+
|
|
1926
|
+
```json
|
|
1927
|
+
{
|
|
1928
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1929
|
+
"name": "Newsletters",
|
|
1930
|
+
"description": "Monthly updates",
|
|
1931
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1932
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1933
|
+
}
|
|
1934
|
+
```
|
|
1935
|
+
|
|
1359
1936
|
---
|
|
1360
1937
|
|
|
1361
1938
|
### CampaignGroups.get()
|
|
@@ -1376,6 +1953,18 @@ Get a campaign group by ID.
|
|
|
1376
1953
|
response = LoopsSdk::CampaignGroups.get(campaign_group_id: "clq7r0s2t0176pvz8hnmpwy01")
|
|
1377
1954
|
```
|
|
1378
1955
|
|
|
1956
|
+
#### Response
|
|
1957
|
+
|
|
1958
|
+
```json
|
|
1959
|
+
{
|
|
1960
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1961
|
+
"name": "Newsletters",
|
|
1962
|
+
"description": "Monthly product updates",
|
|
1963
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1964
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1965
|
+
}
|
|
1966
|
+
```
|
|
1967
|
+
|
|
1379
1968
|
---
|
|
1380
1969
|
|
|
1381
1970
|
### CampaignGroups.update()
|
|
@@ -1403,13 +1992,25 @@ response = LoopsSdk::CampaignGroups.update(
|
|
|
1403
1992
|
)
|
|
1404
1993
|
```
|
|
1405
1994
|
|
|
1995
|
+
#### Response
|
|
1996
|
+
|
|
1997
|
+
```json
|
|
1998
|
+
{
|
|
1999
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2000
|
+
"name": "Updated name",
|
|
2001
|
+
"description": "Monthly product updates",
|
|
2002
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2003
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2004
|
+
}
|
|
2005
|
+
```
|
|
2006
|
+
|
|
1406
2007
|
---
|
|
1407
2008
|
|
|
1408
|
-
###
|
|
2009
|
+
### WorkflowGroups.list()
|
|
1409
2010
|
|
|
1410
|
-
List
|
|
2011
|
+
List workflow groups.
|
|
1411
2012
|
|
|
1412
|
-
[API Reference](https://loops.so/docs/api-reference/list-
|
|
2013
|
+
[API Reference](https://loops.so/docs/api-reference/list-workflow-groups)
|
|
1413
2014
|
|
|
1414
2015
|
#### Parameters
|
|
1415
2016
|
|
|
@@ -1421,167 +2022,1265 @@ List audience segments.
|
|
|
1421
2022
|
#### Example
|
|
1422
2023
|
|
|
1423
2024
|
```ruby
|
|
1424
|
-
response = LoopsSdk::
|
|
2025
|
+
response = LoopsSdk::WorkflowGroups.list
|
|
2026
|
+
```
|
|
2027
|
+
|
|
2028
|
+
#### Response
|
|
2029
|
+
|
|
2030
|
+
```json
|
|
2031
|
+
{
|
|
2032
|
+
"pagination": {
|
|
2033
|
+
"totalResults": 1,
|
|
2034
|
+
"returnedResults": 1,
|
|
2035
|
+
"perPage": 20,
|
|
2036
|
+
"totalPages": 1,
|
|
2037
|
+
"nextCursor": null,
|
|
2038
|
+
"nextPage": null
|
|
2039
|
+
},
|
|
2040
|
+
"data": [
|
|
2041
|
+
{
|
|
2042
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2043
|
+
"name": "Onboarding",
|
|
2044
|
+
"description": "Signup and activation flows",
|
|
2045
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2046
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2047
|
+
}
|
|
2048
|
+
]
|
|
2049
|
+
}
|
|
1425
2050
|
```
|
|
1426
2051
|
|
|
1427
2052
|
---
|
|
1428
2053
|
|
|
1429
|
-
###
|
|
2054
|
+
### WorkflowGroups.create()
|
|
1430
2055
|
|
|
1431
|
-
|
|
2056
|
+
Create a workflow group.
|
|
1432
2057
|
|
|
1433
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2058
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow-group)
|
|
1434
2059
|
|
|
1435
2060
|
#### Parameters
|
|
1436
2061
|
|
|
1437
|
-
| Name
|
|
1438
|
-
|
|
|
1439
|
-
| `
|
|
2062
|
+
| Name | Type | Required | Notes |
|
|
2063
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
2064
|
+
| `name` | string | Yes | Cannot be the reserved name "Unsorted". |
|
|
2065
|
+
| `description` | string | No | An optional description for the group. |
|
|
1440
2066
|
|
|
1441
2067
|
#### Example
|
|
1442
2068
|
|
|
1443
2069
|
```ruby
|
|
1444
|
-
response = LoopsSdk::
|
|
2070
|
+
response = LoopsSdk::WorkflowGroups.create(name: "Onboarding", description: "Signup flows")
|
|
2071
|
+
```
|
|
2072
|
+
|
|
2073
|
+
#### Response
|
|
2074
|
+
|
|
2075
|
+
```json
|
|
2076
|
+
{
|
|
2077
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2078
|
+
"name": "Onboarding",
|
|
2079
|
+
"description": "Signup flows",
|
|
2080
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2081
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2082
|
+
}
|
|
1445
2083
|
```
|
|
1446
2084
|
|
|
1447
2085
|
---
|
|
1448
2086
|
|
|
1449
|
-
###
|
|
2087
|
+
### WorkflowGroups.get()
|
|
1450
2088
|
|
|
1451
|
-
|
|
2089
|
+
Get a workflow group by ID.
|
|
1452
2090
|
|
|
1453
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2091
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow-group)
|
|
1454
2092
|
|
|
1455
2093
|
#### Parameters
|
|
1456
2094
|
|
|
1457
|
-
| Name
|
|
1458
|
-
|
|
|
1459
|
-
| `
|
|
1460
|
-
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2095
|
+
| Name | Type | Required | Notes |
|
|
2096
|
+
| ------------------- | ------ | -------- | ----- |
|
|
2097
|
+
| `workflow_group_id` | string | Yes | |
|
|
1461
2098
|
|
|
1462
2099
|
#### Example
|
|
1463
2100
|
|
|
1464
2101
|
```ruby
|
|
1465
|
-
response = LoopsSdk::
|
|
2102
|
+
response = LoopsSdk::WorkflowGroups.get(workflow_group_id: "clw8x0y2z0300ycc1lrstvw78")
|
|
2103
|
+
```
|
|
2104
|
+
|
|
2105
|
+
#### Response
|
|
2106
|
+
|
|
2107
|
+
```json
|
|
2108
|
+
{
|
|
2109
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2110
|
+
"name": "Onboarding",
|
|
2111
|
+
"description": "Signup and activation flows",
|
|
2112
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2113
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2114
|
+
}
|
|
1466
2115
|
```
|
|
1467
2116
|
|
|
1468
2117
|
---
|
|
1469
2118
|
|
|
1470
|
-
###
|
|
2119
|
+
### WorkflowGroups.update()
|
|
1471
2120
|
|
|
1472
|
-
|
|
2121
|
+
Update a workflow group's name or description.
|
|
1473
2122
|
|
|
1474
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2123
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow-group)
|
|
1475
2124
|
|
|
1476
2125
|
#### Parameters
|
|
1477
2126
|
|
|
1478
|
-
| Name
|
|
1479
|
-
|
|
|
1480
|
-
| `
|
|
2127
|
+
| Name | Type | Required | Notes |
|
|
2128
|
+
| ------------------- | ------ | -------- | --------------------------------------- |
|
|
2129
|
+
| `workflow_group_id` | string | Yes | |
|
|
2130
|
+
| `name` | string | No | Cannot be the reserved name "Unsorted". |
|
|
2131
|
+
| `description` | string | No | |
|
|
2132
|
+
|
|
2133
|
+
At least one field must be provided.
|
|
1481
2134
|
|
|
1482
2135
|
#### Example
|
|
1483
2136
|
|
|
1484
2137
|
```ruby
|
|
1485
|
-
response = LoopsSdk::
|
|
2138
|
+
response = LoopsSdk::WorkflowGroups.update(
|
|
2139
|
+
workflow_group_id: "clw8x0y2z0300ycc1lrstvw78",
|
|
2140
|
+
name: "Updated name"
|
|
2141
|
+
)
|
|
2142
|
+
```
|
|
2143
|
+
|
|
2144
|
+
#### Response
|
|
2145
|
+
|
|
2146
|
+
```json
|
|
2147
|
+
{
|
|
2148
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2149
|
+
"name": "Updated name",
|
|
2150
|
+
"description": "Signup and activation flows",
|
|
2151
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2152
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2153
|
+
}
|
|
1486
2154
|
```
|
|
1487
2155
|
|
|
1488
2156
|
---
|
|
1489
2157
|
|
|
1490
|
-
###
|
|
2158
|
+
### AudienceSegments.list()
|
|
1491
2159
|
|
|
1492
|
-
|
|
2160
|
+
List audience segments.
|
|
1493
2161
|
|
|
1494
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2162
|
+
[API Reference](https://loops.so/docs/api-reference/list-audience-segments)
|
|
1495
2163
|
|
|
1496
2164
|
#### Parameters
|
|
1497
2165
|
|
|
1498
|
-
| Name
|
|
1499
|
-
|
|
|
1500
|
-
| `
|
|
1501
|
-
| `
|
|
2166
|
+
| Name | Type | Required | Notes |
|
|
2167
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2168
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2169
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
1502
2170
|
|
|
1503
2171
|
#### Example
|
|
1504
2172
|
|
|
1505
2173
|
```ruby
|
|
1506
|
-
response = LoopsSdk::
|
|
2174
|
+
response = LoopsSdk::AudienceSegments.list
|
|
2175
|
+
```
|
|
2176
|
+
|
|
2177
|
+
#### Response
|
|
2178
|
+
|
|
2179
|
+
```json
|
|
2180
|
+
{
|
|
2181
|
+
"pagination": {
|
|
2182
|
+
"totalResults": 1,
|
|
2183
|
+
"returnedResults": 1,
|
|
2184
|
+
"perPage": 20,
|
|
2185
|
+
"totalPages": 1,
|
|
2186
|
+
"nextCursor": null,
|
|
2187
|
+
"nextPage": null
|
|
2188
|
+
},
|
|
2189
|
+
"data": [
|
|
2190
|
+
{
|
|
2191
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
2192
|
+
"name": "Power users",
|
|
2193
|
+
"description": "Contacts on the pro plan",
|
|
2194
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2195
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
2196
|
+
"filter": {
|
|
2197
|
+
"match": "all",
|
|
2198
|
+
"conditions": [
|
|
2199
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
2200
|
+
]
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
]
|
|
2204
|
+
}
|
|
1507
2205
|
```
|
|
1508
2206
|
|
|
1509
2207
|
---
|
|
1510
2208
|
|
|
1511
|
-
###
|
|
2209
|
+
### AudienceSegments.get()
|
|
1512
2210
|
|
|
1513
|
-
|
|
2211
|
+
Get an audience segment by ID.
|
|
1514
2212
|
|
|
1515
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2213
|
+
[API Reference](https://loops.so/docs/api-reference/get-audience-segment)
|
|
1516
2214
|
|
|
1517
2215
|
#### Parameters
|
|
1518
2216
|
|
|
1519
|
-
| Name
|
|
1520
|
-
|
|
|
1521
|
-
| `
|
|
1522
|
-
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2217
|
+
| Name | Type | Required | Notes |
|
|
2218
|
+
| ---- | ------ | -------- | ----- |
|
|
2219
|
+
| `audience_segment_id` | string | Yes | |
|
|
1523
2220
|
|
|
1524
2221
|
#### Example
|
|
1525
2222
|
|
|
1526
2223
|
```ruby
|
|
1527
|
-
response = LoopsSdk::
|
|
2224
|
+
response = LoopsSdk::AudienceSegments.get(audience_segment_id: "clr8s1t3u0198qw09iotqzx12")
|
|
2225
|
+
```
|
|
2226
|
+
|
|
2227
|
+
#### Response
|
|
2228
|
+
|
|
2229
|
+
```json
|
|
2230
|
+
{
|
|
2231
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
2232
|
+
"name": "Power users",
|
|
2233
|
+
"description": "Contacts on the pro plan",
|
|
2234
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2235
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
2236
|
+
"filter": {
|
|
2237
|
+
"match": "all",
|
|
2238
|
+
"conditions": [
|
|
2239
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
2240
|
+
]
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
1528
2243
|
```
|
|
1529
2244
|
|
|
1530
2245
|
---
|
|
1531
2246
|
|
|
1532
|
-
###
|
|
2247
|
+
### AudienceSegments.create()
|
|
1533
2248
|
|
|
1534
|
-
Create a
|
|
2249
|
+
Create a new audience segment.
|
|
1535
2250
|
|
|
1536
|
-
[API Reference](https://loops.so/docs/api-reference/create-
|
|
2251
|
+
[API Reference](https://loops.so/docs/api-reference/create-audience-segment)
|
|
1537
2252
|
|
|
1538
2253
|
#### Parameters
|
|
1539
2254
|
|
|
1540
|
-
| Name | Type | Required | Notes
|
|
1541
|
-
| ------------- | ------ | -------- |
|
|
1542
|
-
| `name` | string | Yes |
|
|
1543
|
-
| `
|
|
2255
|
+
| Name | Type | Required | Notes |
|
|
2256
|
+
| ------------- | ------ | -------- | --------------------------------------------------------------------------- |
|
|
2257
|
+
| `name` | string | Yes | Must be unique within the team. |
|
|
2258
|
+
| `filter` | object | Yes | JSON tree of audience conditions with `match` and `conditions`. See the [API reference](https://loops.so/docs/api-reference/create-audience-segment#body-filter). |
|
|
2259
|
+
| `description` | string | No | |
|
|
1544
2260
|
|
|
1545
2261
|
#### Example
|
|
1546
2262
|
|
|
1547
2263
|
```ruby
|
|
1548
|
-
response = LoopsSdk::
|
|
2264
|
+
response = LoopsSdk::AudienceSegments.create(
|
|
2265
|
+
name: "Power users",
|
|
2266
|
+
filter: {
|
|
2267
|
+
match: "all",
|
|
2268
|
+
conditions: [
|
|
2269
|
+
{ type: "property", key: "plan", operator: "equals", value: "pro" }
|
|
2270
|
+
]
|
|
2271
|
+
}
|
|
2272
|
+
)
|
|
2273
|
+
```
|
|
2274
|
+
|
|
2275
|
+
#### Response
|
|
2276
|
+
|
|
2277
|
+
```json
|
|
2278
|
+
{
|
|
2279
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
2280
|
+
"name": "Power users",
|
|
2281
|
+
"description": null,
|
|
2282
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2283
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
2284
|
+
"filter": {
|
|
2285
|
+
"match": "all",
|
|
2286
|
+
"conditions": [
|
|
2287
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
2288
|
+
]
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
1549
2291
|
```
|
|
1550
2292
|
|
|
1551
2293
|
---
|
|
1552
2294
|
|
|
1553
|
-
###
|
|
2295
|
+
### Workflows.list()
|
|
1554
2296
|
|
|
1555
|
-
|
|
2297
|
+
List workflows.
|
|
1556
2298
|
|
|
1557
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2299
|
+
[API Reference](https://loops.so/docs/api-reference/list-workflows)
|
|
1558
2300
|
|
|
1559
2301
|
#### Parameters
|
|
1560
2302
|
|
|
1561
|
-
| Name
|
|
1562
|
-
|
|
|
1563
|
-
| `
|
|
2303
|
+
| Name | Type | Required | Notes |
|
|
2304
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2305
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2306
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
1564
2307
|
|
|
1565
2308
|
#### Example
|
|
1566
2309
|
|
|
1567
2310
|
```ruby
|
|
1568
|
-
response = LoopsSdk::
|
|
2311
|
+
response = LoopsSdk::Workflows.list
|
|
2312
|
+
```
|
|
2313
|
+
|
|
2314
|
+
#### Response
|
|
2315
|
+
|
|
2316
|
+
```json
|
|
2317
|
+
{
|
|
2318
|
+
"pagination": {
|
|
2319
|
+
"totalResults": 1,
|
|
2320
|
+
"returnedResults": 1,
|
|
2321
|
+
"perPage": 20,
|
|
2322
|
+
"totalPages": 1,
|
|
2323
|
+
"nextCursor": null,
|
|
2324
|
+
"nextPage": null
|
|
2325
|
+
},
|
|
2326
|
+
"data": [
|
|
2327
|
+
{
|
|
2328
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2329
|
+
"url": "https://app.loops.so/workflows/clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2330
|
+
"name": "Onboarding",
|
|
2331
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2332
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2333
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2334
|
+
}
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
1569
2337
|
```
|
|
1570
2338
|
|
|
1571
2339
|
---
|
|
1572
2340
|
|
|
1573
|
-
###
|
|
2341
|
+
### Workflows.create()
|
|
1574
2342
|
|
|
1575
|
-
|
|
2343
|
+
Create a draft workflow with a blank trigger and exit node.
|
|
1576
2344
|
|
|
1577
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
2345
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow)
|
|
1578
2346
|
|
|
1579
2347
|
#### Parameters
|
|
1580
2348
|
|
|
1581
|
-
| Name
|
|
1582
|
-
|
|
|
1583
|
-
| `
|
|
1584
|
-
| `
|
|
2349
|
+
| Name | Type | Required | Notes |
|
|
2350
|
+
| -------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2351
|
+
| `name` | string | Yes | |
|
|
2352
|
+
| `description` | string | No | |
|
|
2353
|
+
| `mailing_list_id` | string | No | The mailing list the workflow sends to. |
|
|
2354
|
+
| `workflow_group_id` | string | No | The workflow group to create this workflow in. Defaults to the team's Unsorted group when omitted. |
|
|
2355
|
+
|
|
2356
|
+
#### Example
|
|
2357
|
+
|
|
2358
|
+
```ruby
|
|
2359
|
+
response = LoopsSdk::Workflows.create(name: "Welcome series")
|
|
2360
|
+
```
|
|
2361
|
+
|
|
2362
|
+
#### Response
|
|
2363
|
+
|
|
2364
|
+
```json
|
|
2365
|
+
{
|
|
2366
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2367
|
+
"status": "Draft",
|
|
2368
|
+
"name": "Welcome series",
|
|
2369
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2370
|
+
"mailingListId": null,
|
|
2371
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2372
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2373
|
+
"nodes": {
|
|
2374
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2375
|
+
"typeName": "BlankTrigger",
|
|
2376
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2377
|
+
},
|
|
2378
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2379
|
+
"typeName": "ExitAction",
|
|
2380
|
+
"nextNodeIds": []
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
```
|
|
2385
|
+
|
|
2386
|
+
---
|
|
2387
|
+
|
|
2388
|
+
### Workflows.get()
|
|
2389
|
+
|
|
2390
|
+
Get a simplified workflow graph.
|
|
2391
|
+
|
|
2392
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow)
|
|
2393
|
+
|
|
2394
|
+
#### Parameters
|
|
2395
|
+
|
|
2396
|
+
| Name | Type | Required | Notes |
|
|
2397
|
+
| ---- | ------ | -------- | ----- |
|
|
2398
|
+
| `workflow_id` | string | Yes | |
|
|
2399
|
+
|
|
2400
|
+
#### Example
|
|
2401
|
+
|
|
2402
|
+
```ruby
|
|
2403
|
+
response = LoopsSdk::Workflows.get(workflow_id: "cls9t2u4v0210rx20jpuary23")
|
|
2404
|
+
```
|
|
2405
|
+
|
|
2406
|
+
#### Response
|
|
2407
|
+
|
|
2408
|
+
```json
|
|
2409
|
+
{
|
|
2410
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2411
|
+
"status": "Draft",
|
|
2412
|
+
"name": "Onboarding",
|
|
2413
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2414
|
+
"mailingListId": null,
|
|
2415
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2416
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2417
|
+
"nodes": {
|
|
2418
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2419
|
+
"typeName": "SignupTrigger",
|
|
2420
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2421
|
+
},
|
|
2422
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2423
|
+
"typeName": "ExitAction",
|
|
2424
|
+
"nextNodeIds": []
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
```
|
|
2429
|
+
|
|
2430
|
+
---
|
|
2431
|
+
|
|
2432
|
+
### Workflows.update()
|
|
2433
|
+
|
|
2434
|
+
Update a workflow's display properties. To change the mailing list, use `Workflows.change_mailing_list()`.
|
|
2435
|
+
|
|
2436
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow)
|
|
2437
|
+
|
|
2438
|
+
#### Parameters
|
|
2439
|
+
|
|
2440
|
+
| Name | Type | Required | Notes |
|
|
2441
|
+
| ------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2442
|
+
| `workflow_id` | string | Yes | |
|
|
2443
|
+
| `expected_revision_id` | string | Yes | The `workflowRevisionId` from the latest read or mutation. Pass `nil` for older workflows. |
|
|
2444
|
+
| `name` | string | No | |
|
|
2445
|
+
| `description` | string | No | |
|
|
2446
|
+
| `workflow_group_id` | string | No | The workflow group to move this workflow into. |
|
|
2447
|
+
|
|
2448
|
+
At least one of `name`, `description`, or `workflow_group_id` must be provided.
|
|
2449
|
+
|
|
2450
|
+
#### Example
|
|
2451
|
+
|
|
2452
|
+
```ruby
|
|
2453
|
+
response = LoopsSdk::Workflows.update(
|
|
2454
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2455
|
+
expected_revision_id: "rev_123",
|
|
2456
|
+
name: "Updated name"
|
|
2457
|
+
)
|
|
2458
|
+
```
|
|
2459
|
+
|
|
2460
|
+
#### Response
|
|
2461
|
+
|
|
2462
|
+
```json
|
|
2463
|
+
{
|
|
2464
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2465
|
+
"status": "Draft",
|
|
2466
|
+
"name": "Updated name",
|
|
2467
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2468
|
+
"mailingListId": null,
|
|
2469
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2470
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2471
|
+
"nodes": {
|
|
2472
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2473
|
+
"typeName": "BlankTrigger",
|
|
2474
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2475
|
+
},
|
|
2476
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2477
|
+
"typeName": "ExitAction",
|
|
2478
|
+
"nextNodeIds": []
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
```
|
|
2483
|
+
|
|
2484
|
+
---
|
|
2485
|
+
|
|
2486
|
+
### Workflows.delete()
|
|
2487
|
+
|
|
2488
|
+
Delete a workflow. Successful deletion returns no content (`nil`). If the workflow is currently sending or has queued contacts, the API returns `409 Conflict` — retry with `confirm_delete: true` to delete the workflow, stop sending, and cancel queued contacts.
|
|
2489
|
+
|
|
2490
|
+
[API Reference](https://loops.so/docs/api-reference/delete-workflow)
|
|
2491
|
+
|
|
2492
|
+
#### Parameters
|
|
2493
|
+
|
|
2494
|
+
| Name | Type | Required | Notes |
|
|
2495
|
+
| ---------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2496
|
+
| `workflow_id` | string | Yes | |
|
|
2497
|
+
| `expected_revision_id` | string | Yes | The `workflowRevisionId` from the latest read or mutation. Pass `nil` for older workflows. |
|
|
2498
|
+
| `confirm_delete` | boolean | No | Set to `true` after a confirmation-required `409` to confirm deleting a sending workflow or a workflow with queued contacts. |
|
|
2499
|
+
|
|
2500
|
+
#### Example
|
|
2501
|
+
|
|
2502
|
+
```ruby
|
|
2503
|
+
LoopsSdk::Workflows.delete(
|
|
2504
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2505
|
+
expected_revision_id: "rev_123"
|
|
2506
|
+
)
|
|
2507
|
+
|
|
2508
|
+
# After a 409 confirming a sending or queued workflow:
|
|
2509
|
+
LoopsSdk::Workflows.delete(
|
|
2510
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2511
|
+
expected_revision_id: "rev_123",
|
|
2512
|
+
confirm_delete: true
|
|
2513
|
+
)
|
|
2514
|
+
```
|
|
2515
|
+
|
|
2516
|
+
#### Response
|
|
2517
|
+
|
|
2518
|
+
`nil` (HTTP `204 No Content`)
|
|
2519
|
+
|
|
2520
|
+
---
|
|
2521
|
+
|
|
2522
|
+
### Workflows.change_mailing_list()
|
|
2523
|
+
|
|
2524
|
+
Dry run or apply a workflow mailing list change. If queued contacts would be removed, the API returns `"status": "queuedContactsFound"` — retry with `queued_contact_policy: "discard"` to apply.
|
|
2525
|
+
|
|
2526
|
+
[API Reference](https://loops.so/docs/api-reference/change-workflow-mailing-list)
|
|
2527
|
+
|
|
2528
|
+
#### Parameters
|
|
2529
|
+
|
|
2530
|
+
| Name | Type | Required | Notes |
|
|
2531
|
+
| ------------------------ | ------- | -------- | --------------------------------------------------------------------- |
|
|
2532
|
+
| `workflow_id` | string | Yes | |
|
|
2533
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2534
|
+
| `mailing_list_id` | string | Yes | Pass `nil` to clear the mailing list. |
|
|
2535
|
+
| `dry_run` | boolean | No | If `true`, validate without modifying. |
|
|
2536
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
2537
|
+
|
|
2538
|
+
#### Example
|
|
2539
|
+
|
|
2540
|
+
```ruby
|
|
2541
|
+
response = LoopsSdk::Workflows.change_mailing_list(
|
|
2542
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2543
|
+
expected_revision_id: "rev_123",
|
|
2544
|
+
mailing_list_id: "cm06f5v0e45nf0ml5754o9cix",
|
|
2545
|
+
dry_run: true
|
|
2546
|
+
)
|
|
2547
|
+
```
|
|
2548
|
+
|
|
2549
|
+
#### Response
|
|
2550
|
+
|
|
2551
|
+
```json
|
|
2552
|
+
{
|
|
2553
|
+
"status": "updated",
|
|
2554
|
+
"mailingListId": "cm06f5v0e45nf0ml5754o9cix",
|
|
2555
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2556
|
+
"queuedContactCount": 0,
|
|
2557
|
+
"workflow": {
|
|
2558
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2559
|
+
"status": "Draft",
|
|
2560
|
+
"name": "Welcome series",
|
|
2561
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2562
|
+
"mailingListId": "cm06f5v0e45nf0ml5754o9cix",
|
|
2563
|
+
"rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2564
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2565
|
+
"nodes": {
|
|
2566
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2567
|
+
"typeName": "BlankTrigger",
|
|
2568
|
+
"nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"]
|
|
2569
|
+
},
|
|
2570
|
+
"cln1a3b5c7d9e1f3g5h7i9j1": {
|
|
2571
|
+
"typeName": "ExitAction",
|
|
2572
|
+
"nextNodeIds": []
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
```
|
|
2578
|
+
|
|
2579
|
+
---
|
|
2580
|
+
|
|
2581
|
+
### Workflows.get_node()
|
|
2582
|
+
|
|
2583
|
+
Get detailed data for a single workflow node.
|
|
2584
|
+
|
|
2585
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow-node)
|
|
2586
|
+
|
|
2587
|
+
#### Parameters
|
|
2588
|
+
|
|
2589
|
+
| Name | Type | Required | Notes |
|
|
2590
|
+
| ------------ | ------ | -------- | ----- |
|
|
2591
|
+
| `workflow_id`| string | Yes | |
|
|
2592
|
+
| `node_id` | string | Yes | |
|
|
2593
|
+
|
|
2594
|
+
#### Example
|
|
2595
|
+
|
|
2596
|
+
```ruby
|
|
2597
|
+
response = LoopsSdk::Workflows.get_node(workflow_id: "cls9t2u4v0210rx20jpuary23", node_id: "clt0u3v5w0232sy31kqvbzs34")
|
|
2598
|
+
```
|
|
2599
|
+
|
|
2600
|
+
#### Response
|
|
2601
|
+
|
|
2602
|
+
```json
|
|
2603
|
+
{
|
|
2604
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2605
|
+
"workflowId": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2606
|
+
"typeName": "TimerAction",
|
|
2607
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2608
|
+
"amount": 1,
|
|
2609
|
+
"unit": "h",
|
|
2610
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2611
|
+
}
|
|
2612
|
+
```
|
|
2613
|
+
|
|
2614
|
+
---
|
|
2615
|
+
|
|
2616
|
+
### Workflows.get_node_metrics()
|
|
2617
|
+
|
|
2618
|
+
Get all-time engagement metrics for a workflow email node.
|
|
2619
|
+
|
|
2620
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow-node-metrics)
|
|
2621
|
+
|
|
2622
|
+
#### Parameters
|
|
2623
|
+
|
|
2624
|
+
| Name | Type | Required | Notes |
|
|
2625
|
+
| ------------- | ------ | -------- | ----- |
|
|
2626
|
+
| `workflow_id` | string | Yes | |
|
|
2627
|
+
| `node_id` | string | Yes | |
|
|
2628
|
+
|
|
2629
|
+
#### Example
|
|
2630
|
+
|
|
2631
|
+
```ruby
|
|
2632
|
+
response = LoopsSdk::Workflows.get_node_metrics(
|
|
2633
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2634
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34"
|
|
2635
|
+
)
|
|
2636
|
+
```
|
|
2637
|
+
|
|
2638
|
+
#### Response
|
|
2639
|
+
|
|
2640
|
+
```json
|
|
2641
|
+
{
|
|
2642
|
+
"sends": 4210,
|
|
2643
|
+
"opens": 1922,
|
|
2644
|
+
"clicks": 301,
|
|
2645
|
+
"unsubscribes": 12,
|
|
2646
|
+
"spamReports": 1,
|
|
2647
|
+
"hardBounces": 9,
|
|
2648
|
+
"softBounces": 13
|
|
2649
|
+
}
|
|
2650
|
+
```
|
|
2651
|
+
|
|
2652
|
+
---
|
|
2653
|
+
|
|
2654
|
+
### Workflows.create_node()
|
|
2655
|
+
|
|
2656
|
+
Create a new default workflow node.
|
|
2657
|
+
|
|
2658
|
+
Use `insert_mode` to choose placement:
|
|
2659
|
+
- `between` — insert between `from_node_id` and `to_node_id`
|
|
2660
|
+
- `before` — insert before `to_node_id`
|
|
2661
|
+
- `after` — insert after `from_node_id` (source must have exactly one outgoing connection)
|
|
2662
|
+
|
|
2663
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow-node)
|
|
2664
|
+
|
|
2665
|
+
#### Parameters
|
|
2666
|
+
|
|
2667
|
+
| Name | Type | Required | Notes |
|
|
2668
|
+
| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2669
|
+
| `workflow_id` | string | Yes | |
|
|
2670
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2671
|
+
| `insert_mode` | string | Yes | `between`, `before`, or `after`. |
|
|
2672
|
+
| `node_type_name` | string | Yes | One of `AudienceFilter`, `BranchNode`, `ExperimentBranchNode`, `TimerAction`, `SendEmailAction`, `VariantNode`. |
|
|
2673
|
+
| `from_node_id` | string | Cond. | Required for `between` and `after`. Not permitted for `before`. |
|
|
2674
|
+
| `to_node_id` | string | Cond. | Required for `between`. For `before`, provide this or `before_node_id` (not both). Not permitted for `after`. |
|
|
2675
|
+
| `before_node_id` | string | Cond. | Deprecated. For `before`, provide this or `to_node_id` (not both). |
|
|
2676
|
+
|
|
2677
|
+
#### Example
|
|
2678
|
+
|
|
2679
|
+
```ruby
|
|
2680
|
+
response = LoopsSdk::Workflows.create_node(
|
|
2681
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2682
|
+
expected_revision_id: "rev_123",
|
|
2683
|
+
insert_mode: "between",
|
|
2684
|
+
node_type_name: "TimerAction",
|
|
2685
|
+
from_node_id: "node_a",
|
|
2686
|
+
to_node_id: "node_b"
|
|
2687
|
+
)
|
|
2688
|
+
|
|
2689
|
+
response = LoopsSdk::Workflows.create_node(
|
|
2690
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2691
|
+
expected_revision_id: "rev_123",
|
|
2692
|
+
insert_mode: "after",
|
|
2693
|
+
node_type_name: "TimerAction",
|
|
2694
|
+
from_node_id: "node_a"
|
|
2695
|
+
)
|
|
2696
|
+
|
|
2697
|
+
response = LoopsSdk::Workflows.create_node(
|
|
2698
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2699
|
+
expected_revision_id: "rev_123",
|
|
2700
|
+
insert_mode: "before",
|
|
2701
|
+
node_type_name: "TimerAction",
|
|
2702
|
+
to_node_id: "node_b"
|
|
2703
|
+
)
|
|
2704
|
+
```
|
|
2705
|
+
|
|
2706
|
+
#### Response
|
|
2707
|
+
|
|
2708
|
+
```json
|
|
2709
|
+
{
|
|
2710
|
+
"node": {
|
|
2711
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2712
|
+
"typeName": "TimerAction",
|
|
2713
|
+
"nextNodeIds": ["node_b"],
|
|
2714
|
+
"amount": 0,
|
|
2715
|
+
"unit": "m",
|
|
2716
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2717
|
+
},
|
|
2718
|
+
"workflow": {
|
|
2719
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2720
|
+
"status": "Draft",
|
|
2721
|
+
"name": "Welcome series",
|
|
2722
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2723
|
+
"mailingListId": null,
|
|
2724
|
+
"rootNodeId": "node_a",
|
|
2725
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2726
|
+
"nodes": {
|
|
2727
|
+
"node_a": {
|
|
2728
|
+
"typeName": "BlankTrigger",
|
|
2729
|
+
"nextNodeIds": ["cln8p0q2r4s6t8u0v2w4x6z8"]
|
|
2730
|
+
},
|
|
2731
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2732
|
+
"typeName": "TimerAction",
|
|
2733
|
+
"nextNodeIds": ["node_b"],
|
|
2734
|
+
"amount": 0,
|
|
2735
|
+
"unit": "m"
|
|
2736
|
+
},
|
|
2737
|
+
"node_b": {
|
|
2738
|
+
"typeName": "ExitAction",
|
|
2739
|
+
"nextNodeIds": []
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
```
|
|
2745
|
+
|
|
2746
|
+
---
|
|
2747
|
+
|
|
2748
|
+
### Workflows.update_node()
|
|
2749
|
+
|
|
2750
|
+
Update workflow-node-owned fields for a single node.
|
|
2751
|
+
|
|
2752
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow-node)
|
|
2753
|
+
|
|
2754
|
+
#### Parameters
|
|
2755
|
+
|
|
2756
|
+
| Name | Type | Required | Notes |
|
|
2757
|
+
| ---------------------- | ------ | -------- | ---------------------------------------------------------- |
|
|
2758
|
+
| `workflow_id` | string | Yes | |
|
|
2759
|
+
| `node_id` | string | Yes | |
|
|
2760
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2761
|
+
| `payload` | object | Yes | Node-type-specific fields. See the API reference. |
|
|
2762
|
+
|
|
2763
|
+
#### Example
|
|
2764
|
+
|
|
2765
|
+
```ruby
|
|
2766
|
+
response = LoopsSdk::Workflows.update_node(
|
|
2767
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2768
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2769
|
+
expected_revision_id: "rev_123",
|
|
2770
|
+
payload: { amount: 2, unit: "d" }
|
|
2771
|
+
)
|
|
2772
|
+
```
|
|
2773
|
+
|
|
2774
|
+
#### Response
|
|
2775
|
+
|
|
2776
|
+
```json
|
|
2777
|
+
{
|
|
2778
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2779
|
+
"workflowId": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2780
|
+
"typeName": "TimerAction",
|
|
2781
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2782
|
+
"amount": 2,
|
|
2783
|
+
"unit": "d",
|
|
2784
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2785
|
+
"workflow": {
|
|
2786
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2787
|
+
"status": "Draft",
|
|
2788
|
+
"name": "Welcome series",
|
|
2789
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2790
|
+
"mailingListId": null,
|
|
2791
|
+
"rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2792
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2793
|
+
"nodes": {
|
|
2794
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2795
|
+
"typeName": "TimerAction",
|
|
2796
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2797
|
+
"amount": 2,
|
|
2798
|
+
"unit": "d"
|
|
2799
|
+
},
|
|
2800
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2801
|
+
"typeName": "ExitAction",
|
|
2802
|
+
"nextNodeIds": []
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
```
|
|
2808
|
+
|
|
2809
|
+
---
|
|
2810
|
+
|
|
2811
|
+
### Workflows.delete_node()
|
|
2812
|
+
|
|
2813
|
+
Delete a single workflow node. If contacts are queued, the API returns `"status": "queuedContactsFound"` — retry with `queued_contact_policy: "discard"` to delete.
|
|
2814
|
+
|
|
2815
|
+
[API Reference](https://loops.so/docs/api-reference/delete-workflow-node)
|
|
2816
|
+
|
|
2817
|
+
#### Parameters
|
|
2818
|
+
|
|
2819
|
+
| Name | Type | Required | Notes |
|
|
2820
|
+
| ----------------------- | ------- | -------- | ------------------------------ |
|
|
2821
|
+
| `workflow_id` | string | Yes | |
|
|
2822
|
+
| `node_id` | string | Yes | |
|
|
2823
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows.|
|
|
2824
|
+
| `dry_run` | boolean | No | |
|
|
2825
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
2826
|
+
|
|
2827
|
+
#### Example
|
|
2828
|
+
|
|
2829
|
+
```ruby
|
|
2830
|
+
response = LoopsSdk::Workflows.delete_node(
|
|
2831
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2832
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2833
|
+
expected_revision_id: "rev_123",
|
|
2834
|
+
dry_run: true
|
|
2835
|
+
)
|
|
2836
|
+
```
|
|
2837
|
+
|
|
2838
|
+
#### Response
|
|
2839
|
+
|
|
2840
|
+
```json
|
|
2841
|
+
{
|
|
2842
|
+
"status": "deleted",
|
|
2843
|
+
"nodeIds": ["clt0u3v5w0232sy31kqvbzs34"],
|
|
2844
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2845
|
+
"queuedContactCount": 0,
|
|
2846
|
+
"workflow": {
|
|
2847
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2848
|
+
"status": "Draft",
|
|
2849
|
+
"name": "Welcome series",
|
|
2850
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2851
|
+
"mailingListId": null,
|
|
2852
|
+
"rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2853
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2854
|
+
"nodes": {
|
|
2855
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2856
|
+
"typeName": "BlankTrigger",
|
|
2857
|
+
"nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"]
|
|
2858
|
+
},
|
|
2859
|
+
"cln1a3b5c7d9e1f3g5h7i9j1": {
|
|
2860
|
+
"typeName": "ExitAction",
|
|
2861
|
+
"nextNodeIds": []
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
```
|
|
2867
|
+
|
|
2868
|
+
---
|
|
2869
|
+
|
|
2870
|
+
### Workflows.add_branch()
|
|
2871
|
+
|
|
2872
|
+
Add a branch and child node under an existing `BranchNode` or `ExperimentBranchNode`.
|
|
2873
|
+
|
|
2874
|
+
[API Reference](https://loops.so/docs/api-reference/add-workflow-branch)
|
|
2875
|
+
|
|
2876
|
+
#### Parameters
|
|
2877
|
+
|
|
2878
|
+
| Name | Type | Required | Notes |
|
|
2879
|
+
| ---------------------- | ------ | -------- | ------------------------------- |
|
|
2880
|
+
| `workflow_id` | string | Yes | |
|
|
2881
|
+
| `node_id` | string | Yes | The branch or experiment node. |
|
|
2882
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2883
|
+
|
|
2884
|
+
#### Example
|
|
2885
|
+
|
|
2886
|
+
```ruby
|
|
2887
|
+
response = LoopsSdk::Workflows.add_branch(
|
|
2888
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2889
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2890
|
+
expected_revision_id: "rev_123"
|
|
2891
|
+
)
|
|
2892
|
+
```
|
|
2893
|
+
|
|
2894
|
+
#### Response
|
|
2895
|
+
|
|
2896
|
+
```json
|
|
2897
|
+
{
|
|
2898
|
+
"node": {
|
|
2899
|
+
"id": "cln0a2b4c6d8e0f2g4h6i8j0",
|
|
2900
|
+
"typeName": "AudienceFilter",
|
|
2901
|
+
"nextNodeIds": [],
|
|
2902
|
+
"appliesDownstream": false,
|
|
2903
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2904
|
+
},
|
|
2905
|
+
"workflow": {
|
|
2906
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2907
|
+
"status": "Draft",
|
|
2908
|
+
"name": "Welcome series",
|
|
2909
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2910
|
+
"mailingListId": null,
|
|
2911
|
+
"rootNodeId": "clt0u3v5w0232sy31kqvbzs34",
|
|
2912
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2913
|
+
"nodes": {
|
|
2914
|
+
"clt0u3v5w0232sy31kqvbzs34": {
|
|
2915
|
+
"typeName": "BranchNode",
|
|
2916
|
+
"nextNodeIds": ["cln0a2b4c6d8e0f2g4h6i8j0"]
|
|
2917
|
+
},
|
|
2918
|
+
"cln0a2b4c6d8e0f2g4h6i8j0": {
|
|
2919
|
+
"typeName": "AudienceFilter",
|
|
2920
|
+
"nextNodeIds": []
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
```
|
|
2926
|
+
|
|
2927
|
+
---
|
|
2928
|
+
|
|
2929
|
+
### Workflows.reroute_node()
|
|
2930
|
+
|
|
2931
|
+
Reroute a source node's outgoing connection to another valid target node. The source node must have exactly one outgoing connection. Branch and experiment branch nodes cannot be rerouted with this endpoint.
|
|
2932
|
+
|
|
2933
|
+
[API Reference](https://loops.so/docs/api-reference/reroute-node-connection)
|
|
2934
|
+
|
|
2935
|
+
#### Parameters
|
|
2936
|
+
|
|
2937
|
+
| Name | Type | Required | Notes |
|
|
2938
|
+
| ---------------------- | ------ | -------- | ------------------------------------------ |
|
|
2939
|
+
| `workflow_id` | string | Yes | |
|
|
2940
|
+
| `node_id` | string | Yes | The source node whose connection to move. |
|
|
2941
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2942
|
+
| `new_target_node_id` | string | Yes | The node that should receive the connection. |
|
|
2943
|
+
|
|
2944
|
+
#### Example
|
|
2945
|
+
|
|
2946
|
+
```ruby
|
|
2947
|
+
response = LoopsSdk::Workflows.reroute_node(
|
|
2948
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2949
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2950
|
+
expected_revision_id: "rev_123",
|
|
2951
|
+
new_target_node_id: "cln3c5d7e9f1g3h5i7j9k1l3"
|
|
2952
|
+
)
|
|
2953
|
+
```
|
|
2954
|
+
|
|
2955
|
+
#### Response
|
|
2956
|
+
|
|
2957
|
+
```json
|
|
2958
|
+
{
|
|
2959
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2960
|
+
"typeName": "SignupTrigger",
|
|
2961
|
+
"nextNodeIds": ["cln3c5d7e9f1g3h5i7j9k1l3"],
|
|
2962
|
+
"workflowRevisionId": "clx7a3b5c7d9e1f3g5h7i9j2",
|
|
2963
|
+
"workflow": {
|
|
2964
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2965
|
+
"workflowRevisionId": "clx7a3b5c7d9e1f3g5h7i9j2",
|
|
2966
|
+
"status": "Draft",
|
|
2967
|
+
"name": "Welcome series",
|
|
2968
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2969
|
+
"mailingListId": "clm2k8j4h6g0f8d6s4a2b0z8",
|
|
2970
|
+
"rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2971
|
+
"nodes": {
|
|
2972
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2973
|
+
"typeName": "SignupTrigger",
|
|
2974
|
+
"nextNodeIds": ["cln3c5d7e9f1g3h5i7j9k1l3"]
|
|
2975
|
+
},
|
|
2976
|
+
"cln3c5d7e9f1g3h5i7j9k1l3": {
|
|
2977
|
+
"typeName": "SendEmailAction",
|
|
2978
|
+
"nextNodeIds": [],
|
|
2979
|
+
"emailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
2980
|
+
"subject": "Welcome to Acme!"
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
```
|
|
2986
|
+
|
|
2987
|
+
---
|
|
2988
|
+
|
|
2989
|
+
### Workflows.delete_node_recursive()
|
|
2990
|
+
|
|
2991
|
+
Delete a node and its downstream subtree.
|
|
2992
|
+
|
|
2993
|
+
[API Reference](https://loops.so/docs/api-reference/delete-workflow-nodes)
|
|
2994
|
+
|
|
2995
|
+
#### Parameters
|
|
2996
|
+
|
|
2997
|
+
| Name | Type | Required | Notes |
|
|
2998
|
+
| ----------------------- | ------- | -------- | ------------------------------ |
|
|
2999
|
+
| `workflow_id` | string | Yes | |
|
|
3000
|
+
| `node_id` | string | Yes | Root of the subtree to delete. |
|
|
3001
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows.|
|
|
3002
|
+
| `dry_run` | boolean | No | |
|
|
3003
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
3004
|
+
|
|
3005
|
+
#### Example
|
|
3006
|
+
|
|
3007
|
+
```ruby
|
|
3008
|
+
response = LoopsSdk::Workflows.delete_node_recursive(
|
|
3009
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
3010
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
3011
|
+
expected_revision_id: "rev_123",
|
|
3012
|
+
queued_contact_policy: "discard"
|
|
3013
|
+
)
|
|
3014
|
+
```
|
|
3015
|
+
|
|
3016
|
+
#### Response
|
|
3017
|
+
|
|
3018
|
+
```json
|
|
3019
|
+
{
|
|
3020
|
+
"status": "deleted",
|
|
3021
|
+
"nodeIds": [
|
|
3022
|
+
"clt0u3v5w0232sy31kqvbzs34",
|
|
3023
|
+
"cln9q1r3s5t7u9v1w3x5y7z9"
|
|
3024
|
+
],
|
|
3025
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
3026
|
+
"queuedContactCount": 0,
|
|
3027
|
+
"workflow": {
|
|
3028
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
3029
|
+
"status": "Draft",
|
|
3030
|
+
"name": "Welcome series",
|
|
3031
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
3032
|
+
"mailingListId": null,
|
|
3033
|
+
"rootNodeId": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
3034
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
3035
|
+
"nodes": {
|
|
3036
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
3037
|
+
"typeName": "BlankTrigger",
|
|
3038
|
+
"nextNodeIds": ["cln1a3b5c7d9e1f3g5h7i9j1"]
|
|
3039
|
+
},
|
|
3040
|
+
"cln1a3b5c7d9e1f3g5h7i9j1": {
|
|
3041
|
+
"typeName": "ExitAction",
|
|
3042
|
+
"nextNodeIds": []
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
```
|
|
3048
|
+
|
|
3049
|
+
---
|
|
3050
|
+
|
|
3051
|
+
### EventPatterns.list()
|
|
3052
|
+
|
|
3053
|
+
List event patterns available to workflow event trigger nodes.
|
|
3054
|
+
|
|
3055
|
+
[API Reference](https://loops.so/docs/api-reference/list-event-patterns)
|
|
3056
|
+
|
|
3057
|
+
#### Parameters
|
|
3058
|
+
|
|
3059
|
+
| Name | Type | Required | Notes |
|
|
3060
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
3061
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
3062
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
3063
|
+
|
|
3064
|
+
#### Example
|
|
3065
|
+
|
|
3066
|
+
```ruby
|
|
3067
|
+
response = LoopsSdk::EventPatterns.list
|
|
3068
|
+
```
|
|
3069
|
+
|
|
3070
|
+
#### Response
|
|
3071
|
+
|
|
3072
|
+
```json
|
|
3073
|
+
{
|
|
3074
|
+
"pagination": {
|
|
3075
|
+
"totalResults": 1,
|
|
3076
|
+
"returnedResults": 1,
|
|
3077
|
+
"perPage": 20,
|
|
3078
|
+
"totalPages": 1,
|
|
3079
|
+
"nextCursor": null,
|
|
3080
|
+
"nextPage": null
|
|
3081
|
+
},
|
|
3082
|
+
"data": [
|
|
3083
|
+
{
|
|
3084
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
3085
|
+
"eventName": "signup",
|
|
3086
|
+
"incomingWebhookPlatform": null
|
|
3087
|
+
}
|
|
3088
|
+
]
|
|
3089
|
+
}
|
|
3090
|
+
```
|
|
3091
|
+
|
|
3092
|
+
---
|
|
3093
|
+
|
|
3094
|
+
### EventPatterns.get()
|
|
3095
|
+
|
|
3096
|
+
Get an event pattern by ID.
|
|
3097
|
+
|
|
3098
|
+
[API Reference](https://loops.so/docs/api-reference/get-event-pattern)
|
|
3099
|
+
|
|
3100
|
+
#### Parameters
|
|
3101
|
+
|
|
3102
|
+
| Name | Type | Required | Notes |
|
|
3103
|
+
| ------------------ | ------ | -------- | ----- |
|
|
3104
|
+
| `event_pattern_id` | string | Yes | |
|
|
3105
|
+
|
|
3106
|
+
#### Example
|
|
3107
|
+
|
|
3108
|
+
```ruby
|
|
3109
|
+
response = LoopsSdk::EventPatterns.get(event_pattern_id: "cle1v2e3n4t5p6a7t8t9e0r1")
|
|
3110
|
+
```
|
|
3111
|
+
|
|
3112
|
+
#### Response
|
|
3113
|
+
|
|
3114
|
+
```json
|
|
3115
|
+
{
|
|
3116
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
3117
|
+
"eventName": "signup",
|
|
3118
|
+
"eventProperties": [
|
|
3119
|
+
{ "name": "plan", "type": "string" },
|
|
3120
|
+
{ "name": "trialDays", "type": "number" }
|
|
3121
|
+
],
|
|
3122
|
+
"incomingWebhookPlatform": null
|
|
3123
|
+
}
|
|
3124
|
+
```
|
|
3125
|
+
|
|
3126
|
+
---
|
|
3127
|
+
|
|
3128
|
+
### EventPatterns.get_by_name()
|
|
3129
|
+
|
|
3130
|
+
Get an event pattern by event name. Event names are case-sensitive.
|
|
3131
|
+
|
|
3132
|
+
[API Reference](https://loops.so/docs/api-reference/get-event-pattern-by-name)
|
|
3133
|
+
|
|
3134
|
+
#### Parameters
|
|
3135
|
+
|
|
3136
|
+
| Name | Type | Required | Notes |
|
|
3137
|
+
| ------------ | ------ | -------- | ----- |
|
|
3138
|
+
| `event_name` | string | Yes | |
|
|
3139
|
+
|
|
3140
|
+
#### Example
|
|
3141
|
+
|
|
3142
|
+
```ruby
|
|
3143
|
+
response = LoopsSdk::EventPatterns.get_by_name(event_name: "signup")
|
|
3144
|
+
```
|
|
3145
|
+
|
|
3146
|
+
#### Response
|
|
3147
|
+
|
|
3148
|
+
```json
|
|
3149
|
+
{
|
|
3150
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
3151
|
+
"eventName": "signup",
|
|
3152
|
+
"eventProperties": [
|
|
3153
|
+
{ "name": "plan", "type": "string" },
|
|
3154
|
+
{ "name": "trialDays", "type": "number" }
|
|
3155
|
+
],
|
|
3156
|
+
"incomingWebhookPlatform": null
|
|
3157
|
+
}
|
|
3158
|
+
```
|
|
3159
|
+
|
|
3160
|
+
---
|
|
3161
|
+
|
|
3162
|
+
### TransactionalGroups.list()
|
|
3163
|
+
|
|
3164
|
+
List transactional groups.
|
|
3165
|
+
|
|
3166
|
+
[API Reference](https://loops.so/docs/api-reference/list-transactional-groups)
|
|
3167
|
+
|
|
3168
|
+
#### Parameters
|
|
3169
|
+
|
|
3170
|
+
| Name | Type | Required | Notes |
|
|
3171
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
3172
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
3173
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
3174
|
+
|
|
3175
|
+
#### Example
|
|
3176
|
+
|
|
3177
|
+
```ruby
|
|
3178
|
+
response = LoopsSdk::TransactionalGroups.list
|
|
3179
|
+
```
|
|
3180
|
+
|
|
3181
|
+
#### Response
|
|
3182
|
+
|
|
3183
|
+
```json
|
|
3184
|
+
{
|
|
3185
|
+
"pagination": {
|
|
3186
|
+
"totalResults": 1,
|
|
3187
|
+
"returnedResults": 1,
|
|
3188
|
+
"perPage": 20,
|
|
3189
|
+
"totalPages": 1,
|
|
3190
|
+
"nextCursor": null,
|
|
3191
|
+
"nextPage": null
|
|
3192
|
+
},
|
|
3193
|
+
"data": [
|
|
3194
|
+
{
|
|
3195
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
3196
|
+
"name": "Onboarding",
|
|
3197
|
+
"description": "Top of funnel campaigns",
|
|
3198
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
3199
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
3200
|
+
}
|
|
3201
|
+
]
|
|
3202
|
+
}
|
|
3203
|
+
```
|
|
3204
|
+
|
|
3205
|
+
---
|
|
3206
|
+
|
|
3207
|
+
### TransactionalGroups.create()
|
|
3208
|
+
|
|
3209
|
+
Create a transactional group.
|
|
3210
|
+
|
|
3211
|
+
[API Reference](https://loops.so/docs/api-reference/create-transactional-group)
|
|
3212
|
+
|
|
3213
|
+
#### Parameters
|
|
3214
|
+
|
|
3215
|
+
| Name | Type | Required | Notes |
|
|
3216
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
3217
|
+
| `name` | string | Yes | Cannot be the reserved name "Unsorted". |
|
|
3218
|
+
| `description` | string | No | An optional description for the group. |
|
|
3219
|
+
|
|
3220
|
+
#### Example
|
|
3221
|
+
|
|
3222
|
+
```ruby
|
|
3223
|
+
response = LoopsSdk::TransactionalGroups.create(name: "Account emails")
|
|
3224
|
+
```
|
|
3225
|
+
|
|
3226
|
+
#### Response
|
|
3227
|
+
|
|
3228
|
+
```json
|
|
3229
|
+
{
|
|
3230
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
3231
|
+
"name": "Account emails",
|
|
3232
|
+
"description": "",
|
|
3233
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
3234
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
3235
|
+
}
|
|
3236
|
+
```
|
|
3237
|
+
|
|
3238
|
+
---
|
|
3239
|
+
|
|
3240
|
+
### TransactionalGroups.get()
|
|
3241
|
+
|
|
3242
|
+
Get a transactional group by ID.
|
|
3243
|
+
|
|
3244
|
+
[API Reference](https://loops.so/docs/api-reference/get-transactional-group)
|
|
3245
|
+
|
|
3246
|
+
#### Parameters
|
|
3247
|
+
|
|
3248
|
+
| Name | Type | Required | Notes |
|
|
3249
|
+
| ---- | ------ | -------- | ----- |
|
|
3250
|
+
| `transactional_group_id` | string | Yes | |
|
|
3251
|
+
|
|
3252
|
+
#### Example
|
|
3253
|
+
|
|
3254
|
+
```ruby
|
|
3255
|
+
response = LoopsSdk::TransactionalGroups.get(transactional_group_id: "clv2w3x4y0288xbb0kqrsuv67")
|
|
3256
|
+
```
|
|
3257
|
+
|
|
3258
|
+
#### Response
|
|
3259
|
+
|
|
3260
|
+
```json
|
|
3261
|
+
{
|
|
3262
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
3263
|
+
"name": "Account emails",
|
|
3264
|
+
"description": "",
|
|
3265
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
3266
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
3267
|
+
}
|
|
3268
|
+
```
|
|
3269
|
+
|
|
3270
|
+
---
|
|
3271
|
+
|
|
3272
|
+
### TransactionalGroups.update()
|
|
3273
|
+
|
|
3274
|
+
Update a transactional group's name or description.
|
|
3275
|
+
|
|
3276
|
+
[API Reference](https://loops.so/docs/api-reference/update-transactional-group)
|
|
3277
|
+
|
|
3278
|
+
#### Parameters
|
|
3279
|
+
|
|
3280
|
+
| Name | Type | Required | Notes |
|
|
3281
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
3282
|
+
| `transactional_group_id` | string | Yes | |
|
|
3283
|
+
| `name` | string | No | Cannot be the reserved name "Unsorted". |
|
|
1585
3284
|
| `description` | string | No | |
|
|
1586
3285
|
|
|
1587
3286
|
At least one field must be provided.
|
|
@@ -1595,6 +3294,18 @@ response = LoopsSdk::TransactionalGroups.update(
|
|
|
1595
3294
|
)
|
|
1596
3295
|
```
|
|
1597
3296
|
|
|
3297
|
+
#### Response
|
|
3298
|
+
|
|
3299
|
+
```json
|
|
3300
|
+
{
|
|
3301
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
3302
|
+
"name": "Updated name",
|
|
3303
|
+
"description": "",
|
|
3304
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
3305
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
3306
|
+
}
|
|
3307
|
+
```
|
|
3308
|
+
|
|
1598
3309
|
---
|
|
1599
3310
|
|
|
1600
3311
|
### Uploads.upload()
|