loops_sdk 2.4.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 +478 -15
- data/lib/loops_sdk/base.rb +2 -0
- data/lib/loops_sdk/campaigns.rb +4 -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 +58 -10
- data/lib/loops_sdk.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a8a4baf2050d5fbaeeb96e5c39000b77fb84603d539218df1b001763d265aeab
|
|
4
|
+
data.tar.gz: 707d8a389ae61d4f8c3c0621a6ec4edb4b0d1c822084e2b680b41ecf7f6d6375
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0b31acb878a70e3665a081e26db46e61cd32cf4d4d032560547122f12c74ef5d0fd03824d481b981f836d9d2aa9ba4ccc279b3131a2dfab01dad3e148fa4c6a
|
|
7
|
+
data.tar.gz: 8c7575f7b5882b62bf7d627c36be1ac801f5f31b973c5e72a787c6b61247e5766219642dcc75eab860fbcba4ad9f0e9925e4479d1927c8b58c2d881e96515493
|
data/README.md
CHANGED
|
@@ -120,6 +120,7 @@ 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)
|
|
@@ -134,10 +135,15 @@ You can use custom contact properties in API calls. Please make sure to [add cus
|
|
|
134
135
|
- [Campaigns.create()](#campaignscreate)
|
|
135
136
|
- [Campaigns.get()](#campaignsget)
|
|
136
137
|
- [Campaigns.update()](#campaignsupdate)
|
|
138
|
+
- [Campaigns.metrics()](#campaignsmetrics)
|
|
137
139
|
- [CampaignGroups.list()](#campaigngroupslist)
|
|
138
140
|
- [CampaignGroups.create()](#campaigngroupscreate)
|
|
139
141
|
- [CampaignGroups.get()](#campaigngroupsget)
|
|
140
142
|
- [CampaignGroups.update()](#campaigngroupsupdate)
|
|
143
|
+
- [WorkflowGroups.list()](#workflowgroupslist)
|
|
144
|
+
- [WorkflowGroups.create()](#workflowgroupscreate)
|
|
145
|
+
- [WorkflowGroups.get()](#workflowgroupsget)
|
|
146
|
+
- [WorkflowGroups.update()](#workflowgroupsupdate)
|
|
141
147
|
- [AudienceSegments.list()](#audiencesegmentslist)
|
|
142
148
|
- [AudienceSegments.get()](#audiencesegmentsget)
|
|
143
149
|
- [AudienceSegments.create()](#audiencesegmentscreate)
|
|
@@ -145,12 +151,15 @@ You can use custom contact properties in API calls. Please make sure to [add cus
|
|
|
145
151
|
- [Workflows.create()](#workflowscreate)
|
|
146
152
|
- [Workflows.get()](#workflowsget)
|
|
147
153
|
- [Workflows.update()](#workflowsupdate)
|
|
154
|
+
- [Workflows.delete()](#workflowsdelete)
|
|
148
155
|
- [Workflows.change_mailing_list()](#workflowschange_mailing_list)
|
|
149
156
|
- [Workflows.get_node()](#workflowsget_node)
|
|
157
|
+
- [Workflows.get_node_metrics()](#workflowsget_node_metrics)
|
|
150
158
|
- [Workflows.create_node()](#workflowscreate_node)
|
|
151
159
|
- [Workflows.update_node()](#workflowsupdate_node)
|
|
152
160
|
- [Workflows.delete_node()](#workflowsdelete_node)
|
|
153
161
|
- [Workflows.add_branch()](#workflowsadd_branch)
|
|
162
|
+
- [Workflows.reroute_node()](#workflowsreroute_node)
|
|
154
163
|
- [Workflows.delete_node_recursive()](#workflowsdelete_node_recursive)
|
|
155
164
|
- [EventPatterns.list()](#eventpatternslist)
|
|
156
165
|
- [EventPatterns.get()](#eventpatternsget)
|
|
@@ -998,6 +1007,38 @@ response = LoopsSdk::Transactional.publish(transactional_id: "clfq6dinn000yl70fg
|
|
|
998
1007
|
|
|
999
1008
|
---
|
|
1000
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
|
+
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1001
1042
|
### Transactional.send()
|
|
1002
1043
|
|
|
1003
1044
|
Send a transactional email to a contact. [Learn about sending transactional email](https://loops.so/docs/transactional/guide)
|
|
@@ -1612,6 +1653,40 @@ response = LoopsSdk::Campaigns.update(
|
|
|
1612
1653
|
|
|
1613
1654
|
---
|
|
1614
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
|
+
|
|
1688
|
+
---
|
|
1689
|
+
|
|
1615
1690
|
### EmailMessages.get()
|
|
1616
1691
|
|
|
1617
1692
|
Get an email message, including its LMX content.
|
|
@@ -1931,6 +2006,155 @@ response = LoopsSdk::CampaignGroups.update(
|
|
|
1931
2006
|
|
|
1932
2007
|
---
|
|
1933
2008
|
|
|
2009
|
+
### WorkflowGroups.list()
|
|
2010
|
+
|
|
2011
|
+
List workflow groups.
|
|
2012
|
+
|
|
2013
|
+
[API Reference](https://loops.so/docs/api-reference/list-workflow-groups)
|
|
2014
|
+
|
|
2015
|
+
#### Parameters
|
|
2016
|
+
|
|
2017
|
+
| Name | Type | Required | Notes |
|
|
2018
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2019
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2020
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2021
|
+
|
|
2022
|
+
#### Example
|
|
2023
|
+
|
|
2024
|
+
```ruby
|
|
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
|
+
}
|
|
2050
|
+
```
|
|
2051
|
+
|
|
2052
|
+
---
|
|
2053
|
+
|
|
2054
|
+
### WorkflowGroups.create()
|
|
2055
|
+
|
|
2056
|
+
Create a workflow group.
|
|
2057
|
+
|
|
2058
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow-group)
|
|
2059
|
+
|
|
2060
|
+
#### Parameters
|
|
2061
|
+
|
|
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. |
|
|
2066
|
+
|
|
2067
|
+
#### Example
|
|
2068
|
+
|
|
2069
|
+
```ruby
|
|
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
|
+
}
|
|
2083
|
+
```
|
|
2084
|
+
|
|
2085
|
+
---
|
|
2086
|
+
|
|
2087
|
+
### WorkflowGroups.get()
|
|
2088
|
+
|
|
2089
|
+
Get a workflow group by ID.
|
|
2090
|
+
|
|
2091
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow-group)
|
|
2092
|
+
|
|
2093
|
+
#### Parameters
|
|
2094
|
+
|
|
2095
|
+
| Name | Type | Required | Notes |
|
|
2096
|
+
| ------------------- | ------ | -------- | ----- |
|
|
2097
|
+
| `workflow_group_id` | string | Yes | |
|
|
2098
|
+
|
|
2099
|
+
#### Example
|
|
2100
|
+
|
|
2101
|
+
```ruby
|
|
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
|
+
}
|
|
2115
|
+
```
|
|
2116
|
+
|
|
2117
|
+
---
|
|
2118
|
+
|
|
2119
|
+
### WorkflowGroups.update()
|
|
2120
|
+
|
|
2121
|
+
Update a workflow group's name or description.
|
|
2122
|
+
|
|
2123
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow-group)
|
|
2124
|
+
|
|
2125
|
+
#### Parameters
|
|
2126
|
+
|
|
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.
|
|
2134
|
+
|
|
2135
|
+
#### Example
|
|
2136
|
+
|
|
2137
|
+
```ruby
|
|
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
|
+
}
|
|
2154
|
+
```
|
|
2155
|
+
|
|
2156
|
+
---
|
|
2157
|
+
|
|
1934
2158
|
### AudienceSegments.list()
|
|
1935
2159
|
|
|
1936
2160
|
List audience segments.
|
|
@@ -2102,7 +2326,9 @@ response = LoopsSdk::Workflows.list
|
|
|
2102
2326
|
"data": [
|
|
2103
2327
|
{
|
|
2104
2328
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2329
|
+
"url": "https://app.loops.so/workflows/clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2105
2330
|
"name": "Onboarding",
|
|
2331
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2106
2332
|
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2107
2333
|
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2108
2334
|
}
|
|
@@ -2120,11 +2346,12 @@ Create a draft workflow with a blank trigger and exit node.
|
|
|
2120
2346
|
|
|
2121
2347
|
#### Parameters
|
|
2122
2348
|
|
|
2123
|
-
| Name
|
|
2124
|
-
|
|
|
2125
|
-
| `name`
|
|
2126
|
-
| `description`
|
|
2127
|
-
| `mailing_list_id`
|
|
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. |
|
|
2128
2355
|
|
|
2129
2356
|
#### Example
|
|
2130
2357
|
|
|
@@ -2139,6 +2366,7 @@ response = LoopsSdk::Workflows.create(name: "Welcome series")
|
|
|
2139
2366
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2140
2367
|
"status": "Draft",
|
|
2141
2368
|
"name": "Welcome series",
|
|
2369
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2142
2370
|
"mailingListId": null,
|
|
2143
2371
|
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2144
2372
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
@@ -2182,6 +2410,7 @@ response = LoopsSdk::Workflows.get(workflow_id: "cls9t2u4v0210rx20jpuary23")
|
|
|
2182
2410
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2183
2411
|
"status": "Draft",
|
|
2184
2412
|
"name": "Onboarding",
|
|
2413
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2185
2414
|
"mailingListId": null,
|
|
2186
2415
|
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2187
2416
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
@@ -2214,8 +2443,9 @@ Update a workflow's display properties. To change the mailing list, use `Workflo
|
|
|
2214
2443
|
| `expected_revision_id` | string | Yes | The `workflowRevisionId` from the latest read or mutation. Pass `nil` for older workflows. |
|
|
2215
2444
|
| `name` | string | No | |
|
|
2216
2445
|
| `description` | string | No | |
|
|
2446
|
+
| `workflow_group_id` | string | No | The workflow group to move this workflow into. |
|
|
2217
2447
|
|
|
2218
|
-
At least one of `name` or `
|
|
2448
|
+
At least one of `name`, `description`, or `workflow_group_id` must be provided.
|
|
2219
2449
|
|
|
2220
2450
|
#### Example
|
|
2221
2451
|
|
|
@@ -2234,6 +2464,7 @@ response = LoopsSdk::Workflows.update(
|
|
|
2234
2464
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2235
2465
|
"status": "Draft",
|
|
2236
2466
|
"name": "Updated name",
|
|
2467
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2237
2468
|
"mailingListId": null,
|
|
2238
2469
|
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2239
2470
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
@@ -2252,6 +2483,42 @@ response = LoopsSdk::Workflows.update(
|
|
|
2252
2483
|
|
|
2253
2484
|
---
|
|
2254
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
|
+
|
|
2255
2522
|
### Workflows.change_mailing_list()
|
|
2256
2523
|
|
|
2257
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.
|
|
@@ -2287,7 +2554,25 @@ response = LoopsSdk::Workflows.change_mailing_list(
|
|
|
2287
2554
|
"mailingListId": "cm06f5v0e45nf0ml5754o9cix",
|
|
2288
2555
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2289
2556
|
"queuedContactCount": 0,
|
|
2290
|
-
"
|
|
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
|
+
}
|
|
2291
2576
|
}
|
|
2292
2577
|
```
|
|
2293
2578
|
|
|
@@ -2328,9 +2613,52 @@ response = LoopsSdk::Workflows.get_node(workflow_id: "cls9t2u4v0210rx20jpuary23"
|
|
|
2328
2613
|
|
|
2329
2614
|
---
|
|
2330
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
|
+
|
|
2331
2654
|
### Workflows.create_node()
|
|
2332
2655
|
|
|
2333
|
-
Create a new default workflow node.
|
|
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)
|
|
2334
2662
|
|
|
2335
2663
|
[API Reference](https://loops.so/docs/api-reference/create-workflow-node)
|
|
2336
2664
|
|
|
@@ -2340,11 +2668,11 @@ Create a new default workflow node. Use `insert_mode: "between"` with `from_node
|
|
|
2340
2668
|
| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2341
2669
|
| `workflow_id` | string | Yes | |
|
|
2342
2670
|
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2343
|
-
| `insert_mode` | string | Yes | `between` or `
|
|
2671
|
+
| `insert_mode` | string | Yes | `between`, `before`, or `after`. |
|
|
2344
2672
|
| `node_type_name` | string | Yes | One of `AudienceFilter`, `BranchNode`, `ExperimentBranchNode`, `TimerAction`, `SendEmailAction`, `VariantNode`. |
|
|
2345
|
-
| `from_node_id` | string |
|
|
2346
|
-
| `to_node_id` | string |
|
|
2347
|
-
| `before_node_id` | string |
|
|
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). |
|
|
2348
2676
|
|
|
2349
2677
|
#### Example
|
|
2350
2678
|
|
|
@@ -2357,6 +2685,22 @@ response = LoopsSdk::Workflows.create_node(
|
|
|
2357
2685
|
from_node_id: "node_a",
|
|
2358
2686
|
to_node_id: "node_b"
|
|
2359
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
|
+
)
|
|
2360
2704
|
```
|
|
2361
2705
|
|
|
2362
2706
|
#### Response
|
|
@@ -2375,6 +2719,7 @@ response = LoopsSdk::Workflows.create_node(
|
|
|
2375
2719
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2376
2720
|
"status": "Draft",
|
|
2377
2721
|
"name": "Welcome series",
|
|
2722
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2378
2723
|
"mailingListId": null,
|
|
2379
2724
|
"rootNodeId": "node_a",
|
|
2380
2725
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
@@ -2436,7 +2781,28 @@ response = LoopsSdk::Workflows.update_node(
|
|
|
2436
2781
|
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2437
2782
|
"amount": 2,
|
|
2438
2783
|
"unit": "d",
|
|
2439
|
-
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
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
|
+
}
|
|
2440
2806
|
}
|
|
2441
2807
|
```
|
|
2442
2808
|
|
|
@@ -2477,7 +2843,25 @@ response = LoopsSdk::Workflows.delete_node(
|
|
|
2477
2843
|
"nodeIds": ["clt0u3v5w0232sy31kqvbzs34"],
|
|
2478
2844
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2479
2845
|
"queuedContactCount": 0,
|
|
2480
|
-
"
|
|
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
|
+
}
|
|
2481
2865
|
}
|
|
2482
2866
|
```
|
|
2483
2867
|
|
|
@@ -2522,6 +2906,7 @@ response = LoopsSdk::Workflows.add_branch(
|
|
|
2522
2906
|
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2523
2907
|
"status": "Draft",
|
|
2524
2908
|
"name": "Welcome series",
|
|
2909
|
+
"workflowGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2525
2910
|
"mailingListId": null,
|
|
2526
2911
|
"rootNodeId": "clt0u3v5w0232sy31kqvbzs34",
|
|
2527
2912
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
@@ -2541,6 +2926,66 @@ response = LoopsSdk::Workflows.add_branch(
|
|
|
2541
2926
|
|
|
2542
2927
|
---
|
|
2543
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
|
+
|
|
2544
2989
|
### Workflows.delete_node_recursive()
|
|
2545
2990
|
|
|
2546
2991
|
Delete a node and its downstream subtree.
|
|
@@ -2579,7 +3024,25 @@ response = LoopsSdk::Workflows.delete_node_recursive(
|
|
|
2579
3024
|
],
|
|
2580
3025
|
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2581
3026
|
"queuedContactCount": 0,
|
|
2582
|
-
"
|
|
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
|
+
}
|
|
2583
3046
|
}
|
|
2584
3047
|
```
|
|
2585
3048
|
|
data/lib/loops_sdk/base.rb
CHANGED
data/lib/loops_sdk/campaigns.rb
CHANGED
|
@@ -29,6 +29,10 @@ module LoopsSdk
|
|
|
29
29
|
make_request(method: :post, path: "v1/transactional-emails/#{transactional_id}/publish")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
def metrics(transactional_id:)
|
|
33
|
+
make_request(method: :get, path: "v1/transactional-emails/#{transactional_id}/metrics")
|
|
34
|
+
end
|
|
35
|
+
|
|
32
36
|
def send(transactional_id:, email:, add_to_audience: false, data_variables: {}, attachments: [], headers: {})
|
|
33
37
|
attachments = attachments.map do |attachment|
|
|
34
38
|
attachment.transform_keys { |key| key == :content_type ? :contentType : key }
|
data/lib/loops_sdk/version.rb
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LoopsSdk
|
|
4
|
+
class WorkflowGroups < Base
|
|
5
|
+
class << self
|
|
6
|
+
def list(perPage: 20, cursor: nil)
|
|
7
|
+
make_request(method: :get, path: "v1/workflow-groups", params: { perPage: perPage, cursor: cursor })
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def create(name:, description: nil)
|
|
11
|
+
body = { name: name, description: description }.compact
|
|
12
|
+
make_request(method: :post, path: "v1/workflow-groups", body: body)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def get(workflow_group_id:)
|
|
16
|
+
make_request(method: :get, path: "v1/workflow-groups/#{workflow_group_id}")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update(workflow_group_id:, name: nil, description: nil)
|
|
20
|
+
body = { name: name, description: description }.compact
|
|
21
|
+
make_request(method: :post, path: "v1/workflow-groups/#{workflow_group_id}", body: body)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/loops_sdk/workflows.rb
CHANGED
|
@@ -7,11 +7,12 @@ module LoopsSdk
|
|
|
7
7
|
make_request(method: :get, path: "v1/workflows", params: { perPage: perPage, cursor: cursor })
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def create(name:, description: nil, mailing_list_id: nil)
|
|
10
|
+
def create(name:, description: nil, mailing_list_id: nil, workflow_group_id: nil)
|
|
11
11
|
body = {
|
|
12
12
|
name: name,
|
|
13
13
|
description: description,
|
|
14
|
-
mailingListId: mailing_list_id
|
|
14
|
+
mailingListId: mailing_list_id,
|
|
15
|
+
workflowGroupId: workflow_group_id
|
|
15
16
|
}.compact
|
|
16
17
|
make_request(method: :post, path: "v1/workflows", body: body)
|
|
17
18
|
end
|
|
@@ -20,17 +21,28 @@ module LoopsSdk
|
|
|
20
21
|
make_request(method: :get, path: "v1/workflows/#{workflow_id}")
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def update(workflow_id:, expected_revision_id:, name: nil, description: nil)
|
|
24
|
+
def update(workflow_id:, expected_revision_id:, name: nil, description: nil, workflow_group_id: nil)
|
|
24
25
|
body = {
|
|
25
26
|
expectedRevisionId: expected_revision_id,
|
|
26
27
|
name: name,
|
|
27
|
-
description: description
|
|
28
|
+
description: description,
|
|
29
|
+
workflowGroupId: workflow_group_id
|
|
28
30
|
}.compact
|
|
29
31
|
# expectedRevisionId may be null for older workflows; always include it
|
|
30
32
|
body[:expectedRevisionId] = expected_revision_id
|
|
31
33
|
make_request(method: :post, path: "v1/workflows/#{workflow_id}", body: body)
|
|
32
34
|
end
|
|
33
35
|
|
|
36
|
+
def delete(workflow_id:, expected_revision_id:, confirm_delete: nil)
|
|
37
|
+
body = {
|
|
38
|
+
expectedRevisionId: expected_revision_id,
|
|
39
|
+
confirmDelete: confirm_delete
|
|
40
|
+
}.compact
|
|
41
|
+
# expectedRevisionId may be null for older workflows; always include it
|
|
42
|
+
body[:expectedRevisionId] = expected_revision_id
|
|
43
|
+
make_request(method: :delete, path: "v1/workflows/#{workflow_id}", body: body)
|
|
44
|
+
end
|
|
45
|
+
|
|
34
46
|
def change_mailing_list(workflow_id:, expected_revision_id:, mailing_list_id:, dry_run: nil, queued_contact_policy: nil)
|
|
35
47
|
body = {
|
|
36
48
|
expectedRevisionId: expected_revision_id,
|
|
@@ -48,6 +60,10 @@ module LoopsSdk
|
|
|
48
60
|
make_request(method: :get, path: "v1/workflows/#{workflow_id}/nodes/#{node_id}")
|
|
49
61
|
end
|
|
50
62
|
|
|
63
|
+
def get_node_metrics(workflow_id:, node_id:)
|
|
64
|
+
make_request(method: :get, path: "v1/workflows/#{workflow_id}/nodes/#{node_id}/metrics")
|
|
65
|
+
end
|
|
66
|
+
|
|
51
67
|
def create_node(
|
|
52
68
|
workflow_id:,
|
|
53
69
|
expected_revision_id:,
|
|
@@ -60,12 +76,36 @@ module LoopsSdk
|
|
|
60
76
|
body = {
|
|
61
77
|
expectedRevisionId: expected_revision_id,
|
|
62
78
|
insertMode: insert_mode,
|
|
63
|
-
nodeTypeName: node_type_name
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
nodeTypeName: node_type_name
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
case insert_mode
|
|
83
|
+
when "between"
|
|
84
|
+
raise ArgumentError, "from_node_id and to_node_id are required when insert_mode is \"between\"." if from_node_id.nil? || to_node_id.nil?
|
|
85
|
+
raise ArgumentError, "before_node_id is not permitted when insert_mode is \"between\"." unless before_node_id.nil?
|
|
86
|
+
|
|
87
|
+
body[:fromNodeId] = from_node_id
|
|
88
|
+
body[:toNodeId] = to_node_id
|
|
89
|
+
when "before"
|
|
90
|
+
raise ArgumentError, "from_node_id is not permitted when insert_mode is \"before\"." unless from_node_id.nil?
|
|
91
|
+
raise ArgumentError, "Provide either to_node_id or before_node_id when insert_mode is \"before\", not both." if !to_node_id.nil? && !before_node_id.nil?
|
|
92
|
+
raise ArgumentError, "to_node_id or before_node_id is required when insert_mode is \"before\"." if to_node_id.nil? && before_node_id.nil?
|
|
93
|
+
|
|
94
|
+
if !to_node_id.nil?
|
|
95
|
+
body[:toNodeId] = to_node_id
|
|
96
|
+
else
|
|
97
|
+
body[:beforeNodeId] = before_node_id
|
|
98
|
+
end
|
|
99
|
+
when "after"
|
|
100
|
+
raise ArgumentError, "from_node_id is required when insert_mode is \"after\"." if from_node_id.nil?
|
|
101
|
+
raise ArgumentError, "to_node_id is not permitted when insert_mode is \"after\"." unless to_node_id.nil?
|
|
102
|
+
raise ArgumentError, "before_node_id is not permitted when insert_mode is \"after\"." unless before_node_id.nil?
|
|
103
|
+
|
|
104
|
+
body[:fromNodeId] = from_node_id
|
|
105
|
+
else
|
|
106
|
+
raise ArgumentError, "insert_mode must be \"between\", \"before\", or \"after\"."
|
|
107
|
+
end
|
|
108
|
+
|
|
69
109
|
make_request(method: :post, path: "v1/workflows/#{workflow_id}/nodes", body: body)
|
|
70
110
|
end
|
|
71
111
|
|
|
@@ -92,6 +132,14 @@ module LoopsSdk
|
|
|
92
132
|
make_request(method: :post, path: "v1/workflows/#{workflow_id}/nodes/#{node_id}/add-branch", body: body)
|
|
93
133
|
end
|
|
94
134
|
|
|
135
|
+
def reroute_node(workflow_id:, node_id:, expected_revision_id:, new_target_node_id:)
|
|
136
|
+
body = {
|
|
137
|
+
expectedRevisionId: expected_revision_id,
|
|
138
|
+
newTargetNodeId: new_target_node_id
|
|
139
|
+
}
|
|
140
|
+
make_request(method: :post, path: "v1/workflows/#{workflow_id}/nodes/#{node_id}/reroute", body: body)
|
|
141
|
+
end
|
|
142
|
+
|
|
95
143
|
def delete_node_recursive(workflow_id:, node_id:, expected_revision_id:, dry_run: nil, queued_contact_policy: nil)
|
|
96
144
|
body = {
|
|
97
145
|
expectedRevisionId: expected_revision_id,
|
data/lib/loops_sdk.rb
CHANGED
|
@@ -20,6 +20,7 @@ require_relative "loops_sdk/email_messages"
|
|
|
20
20
|
require_relative "loops_sdk/uploads"
|
|
21
21
|
require_relative "loops_sdk/audience_segments"
|
|
22
22
|
require_relative "loops_sdk/workflows"
|
|
23
|
+
require_relative "loops_sdk/workflow_groups"
|
|
23
24
|
require_relative "loops_sdk/event_patterns"
|
|
24
25
|
require_relative "loops_sdk/transactional_groups"
|
|
25
26
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: loops_sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dan Rowden
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-11-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -53,6 +53,7 @@ files:
|
|
|
53
53
|
- lib/loops_sdk/transactional_groups.rb
|
|
54
54
|
- lib/loops_sdk/uploads.rb
|
|
55
55
|
- lib/loops_sdk/version.rb
|
|
56
|
+
- lib/loops_sdk/workflow_groups.rb
|
|
56
57
|
- lib/loops_sdk/workflows.rb
|
|
57
58
|
homepage: https://loops.so/docs/api-reference
|
|
58
59
|
licenses:
|