loops_sdk 2.2.0 → 2.4.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 +1839 -90
- data/lib/loops_sdk/audience_segments.rb +20 -0
- data/lib/loops_sdk/base.rb +1 -1
- data/lib/loops_sdk/campaign_groups.rb +25 -0
- data/lib/loops_sdk/campaigns.rb +20 -4
- data/lib/loops_sdk/components.rb +9 -0
- data/lib/loops_sdk/email_messages.rb +40 -2
- data/lib/loops_sdk/event_patterns.rb +22 -0
- data/lib/loops_sdk/themes.rb +10 -0
- data/lib/loops_sdk/transactional.rb +24 -1
- data/lib/loops_sdk/transactional_groups.rb +25 -0
- data/lib/loops_sdk/uploads.rb +66 -0
- data/lib/loops_sdk/version.rb +1 -1
- data/lib/loops_sdk/workflows.rb +106 -0
- data/lib/loops_sdk.rb +6 -0
- metadata +8 -2
data/README.md
CHANGED
|
@@ -114,19 +114,56 @@ You can use custom contact properties in API calls. Please make sure to [add cus
|
|
|
114
114
|
- [ContactProperties.list()](#contactpropertieslist)
|
|
115
115
|
- [MailingLists.list()](#mailinglistslist)
|
|
116
116
|
- [Events.send()](#eventssend)
|
|
117
|
-
- [Transactional.send()](#transactionalsend)
|
|
118
117
|
- [Transactional.list()](#transactionallist)
|
|
118
|
+
- [Transactional.create()](#transactionalcreate)
|
|
119
|
+
- [Transactional.get()](#transactionalget)
|
|
120
|
+
- [Transactional.update()](#transactionalupdate)
|
|
121
|
+
- [Transactional.ensure_draft()](#transactionalensure_draft)
|
|
122
|
+
- [Transactional.publish()](#transactionalpublish)
|
|
123
|
+
- [Transactional.send()](#transactionalsend)
|
|
119
124
|
- [DedicatedSendingIps.list()](#dedicatedsendingipslist)
|
|
120
125
|
- [Themes.list()](#themeslist)
|
|
121
126
|
- [Themes.get()](#themesget)
|
|
127
|
+
- [Themes.create()](#themescreate)
|
|
128
|
+
- [Themes.update()](#themesupdate)
|
|
122
129
|
- [Components.list()](#componentslist)
|
|
123
130
|
- [Components.get()](#componentsget)
|
|
131
|
+
- [Components.create()](#componentscreate)
|
|
132
|
+
- [Components.update()](#componentsupdate)
|
|
124
133
|
- [Campaigns.list()](#campaignslist)
|
|
125
134
|
- [Campaigns.create()](#campaignscreate)
|
|
126
135
|
- [Campaigns.get()](#campaignsget)
|
|
127
136
|
- [Campaigns.update()](#campaignsupdate)
|
|
137
|
+
- [CampaignGroups.list()](#campaigngroupslist)
|
|
138
|
+
- [CampaignGroups.create()](#campaigngroupscreate)
|
|
139
|
+
- [CampaignGroups.get()](#campaigngroupsget)
|
|
140
|
+
- [CampaignGroups.update()](#campaigngroupsupdate)
|
|
141
|
+
- [AudienceSegments.list()](#audiencesegmentslist)
|
|
142
|
+
- [AudienceSegments.get()](#audiencesegmentsget)
|
|
143
|
+
- [AudienceSegments.create()](#audiencesegmentscreate)
|
|
144
|
+
- [Workflows.list()](#workflowslist)
|
|
145
|
+
- [Workflows.create()](#workflowscreate)
|
|
146
|
+
- [Workflows.get()](#workflowsget)
|
|
147
|
+
- [Workflows.update()](#workflowsupdate)
|
|
148
|
+
- [Workflows.change_mailing_list()](#workflowschange_mailing_list)
|
|
149
|
+
- [Workflows.get_node()](#workflowsget_node)
|
|
150
|
+
- [Workflows.create_node()](#workflowscreate_node)
|
|
151
|
+
- [Workflows.update_node()](#workflowsupdate_node)
|
|
152
|
+
- [Workflows.delete_node()](#workflowsdelete_node)
|
|
153
|
+
- [Workflows.add_branch()](#workflowsadd_branch)
|
|
154
|
+
- [Workflows.delete_node_recursive()](#workflowsdelete_node_recursive)
|
|
155
|
+
- [EventPatterns.list()](#eventpatternslist)
|
|
156
|
+
- [EventPatterns.get()](#eventpatternsget)
|
|
157
|
+
- [EventPatterns.get_by_name()](#eventpatternsget_by_name)
|
|
128
158
|
- [EmailMessages.get()](#emailmessagesget)
|
|
129
159
|
- [EmailMessages.update()](#emailmessagesupdate)
|
|
160
|
+
- [EmailMessages.preview()](#emailmessagespreview)
|
|
161
|
+
- [EmailMessages.run_guardian()](#emailmessagesrun_guardian)
|
|
162
|
+
- [TransactionalGroups.list()](#transactionalgroupslist)
|
|
163
|
+
- [TransactionalGroups.create()](#transactionalgroupscreate)
|
|
164
|
+
- [TransactionalGroups.get()](#transactionalgroupsget)
|
|
165
|
+
- [TransactionalGroups.update()](#transactionalgroupsupdate)
|
|
166
|
+
- [Uploads.upload()](#uploadsupload)
|
|
130
167
|
|
|
131
168
|
---
|
|
132
169
|
|
|
@@ -206,7 +243,7 @@ This method will return a success or error message:
|
|
|
206
243
|
```json
|
|
207
244
|
{
|
|
208
245
|
"success": true,
|
|
209
|
-
"id": "
|
|
246
|
+
"id": "cll6b3i8901a9jx0oyktl2m4u"
|
|
210
247
|
}
|
|
211
248
|
```
|
|
212
249
|
|
|
@@ -270,7 +307,7 @@ This method will return a success or error message:
|
|
|
270
307
|
```json
|
|
271
308
|
{
|
|
272
309
|
"success": true,
|
|
273
|
-
"id": "
|
|
310
|
+
"id": "cll6b3i8901a9jx0oyktl2m4u"
|
|
274
311
|
}
|
|
275
312
|
```
|
|
276
313
|
|
|
@@ -726,6 +763,241 @@ This method will return a success or error:
|
|
|
726
763
|
|
|
727
764
|
---
|
|
728
765
|
|
|
766
|
+
### Transactional.list()
|
|
767
|
+
|
|
768
|
+
List transactional emails, most recently created first.
|
|
769
|
+
|
|
770
|
+
[API Reference](https://loops.so/docs/api-reference/list-transactional-emails)
|
|
771
|
+
|
|
772
|
+
#### Parameters
|
|
773
|
+
|
|
774
|
+
| Name | Type | Required | Notes |
|
|
775
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
776
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
777
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
778
|
+
|
|
779
|
+
#### Example
|
|
780
|
+
|
|
781
|
+
```ruby
|
|
782
|
+
response = LoopsSdk::Transactional.list
|
|
783
|
+
|
|
784
|
+
response = LoopsSdk::Transactional.list(perPage: 15, cursor: "cursor_value")
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
#### Response
|
|
788
|
+
|
|
789
|
+
```json
|
|
790
|
+
{
|
|
791
|
+
"pagination": {
|
|
792
|
+
"totalResults": 23,
|
|
793
|
+
"returnedResults": 20,
|
|
794
|
+
"perPage": 20,
|
|
795
|
+
"totalPages": 2,
|
|
796
|
+
"nextCursor": "clyo0q4wo01p59fsecyxqsh38",
|
|
797
|
+
"nextPage": "https://app.loops.so/api/v1/transactional-emails?cursor=clyo0q4wo01p59fsecyxqsh38&perPage=20"
|
|
798
|
+
},
|
|
799
|
+
"data": [
|
|
800
|
+
{
|
|
801
|
+
"id": "clfn0k1yg001imo0fdeqg30i8",
|
|
802
|
+
"name": "Welcome email",
|
|
803
|
+
"draftEmailMessageId": null,
|
|
804
|
+
"publishedEmailMessageId": "cly8k3m0n0044jpx2bghepq45",
|
|
805
|
+
"createdAt": "2023-11-06T17:48:07.249Z",
|
|
806
|
+
"updatedAt": "2023-11-06T17:48:07.249Z",
|
|
807
|
+
"dataVariables": ["confirmationUrl"]
|
|
808
|
+
}
|
|
809
|
+
]
|
|
810
|
+
}
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
---
|
|
814
|
+
|
|
815
|
+
### Transactional.create()
|
|
816
|
+
|
|
817
|
+
Create a transactional email. An empty draft email message is created automatically.
|
|
818
|
+
|
|
819
|
+
[API Reference](https://loops.so/docs/api-reference/create-transactional-email)
|
|
820
|
+
|
|
821
|
+
#### Parameters
|
|
822
|
+
|
|
823
|
+
| Name | Type | Required | Notes |
|
|
824
|
+
| ------------------------ | ------ | -------- | ------------------------------------------------------- |
|
|
825
|
+
| `name` | string | Yes | |
|
|
826
|
+
| `transactional_group_id` | string | No | The ID of the group to add this transactional email to. |
|
|
827
|
+
|
|
828
|
+
#### Example
|
|
829
|
+
|
|
830
|
+
```ruby
|
|
831
|
+
response = LoopsSdk::Transactional.create(name: "Welcome email")
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
#### Response
|
|
835
|
+
|
|
836
|
+
Returns the transactional email with `draftEmailMessageId` and `draftEmailMessageContentRevisionId`. Use these when updating the draft via `EmailMessages.update()`.
|
|
837
|
+
|
|
838
|
+
```json
|
|
839
|
+
{
|
|
840
|
+
"id": "clfq6dinn000yl70fgwwyp82l",
|
|
841
|
+
"name": "Welcome email",
|
|
842
|
+
"draftEmailMessageId": "cly8k3m0n0044jpx2bghepq45",
|
|
843
|
+
"draftEmailMessageContentRevisionId": "clm9n4o6p0088lrz4dijslt67",
|
|
844
|
+
"publishedEmailMessageId": null,
|
|
845
|
+
"createdAt": "2023-11-06T17:48:07.249Z",
|
|
846
|
+
"updatedAt": "2023-11-06T17:48:07.249Z",
|
|
847
|
+
"dataVariables": []
|
|
848
|
+
}
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
---
|
|
852
|
+
|
|
853
|
+
### Transactional.get()
|
|
854
|
+
|
|
855
|
+
Get a single transactional email by ID.
|
|
856
|
+
|
|
857
|
+
[API Reference](https://loops.so/docs/api-reference/get-transactional-email)
|
|
858
|
+
|
|
859
|
+
#### Parameters
|
|
860
|
+
|
|
861
|
+
| Name | Type | Required | Notes |
|
|
862
|
+
| ------------------ | ------ | -------- | ----- |
|
|
863
|
+
| `transactional_id` | string | Yes | |
|
|
864
|
+
|
|
865
|
+
#### Example
|
|
866
|
+
|
|
867
|
+
```ruby
|
|
868
|
+
response = LoopsSdk::Transactional.get(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
#### Response
|
|
872
|
+
|
|
873
|
+
```json
|
|
874
|
+
{
|
|
875
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
876
|
+
"name": "Sign up confirmation",
|
|
877
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
878
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
879
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
880
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
881
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
882
|
+
"dataVariables": ["confirmationUrl"]
|
|
883
|
+
}
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
---
|
|
887
|
+
|
|
888
|
+
### Transactional.update()
|
|
889
|
+
|
|
890
|
+
Update a transactional email's name.
|
|
891
|
+
|
|
892
|
+
[API Reference](https://loops.so/docs/api-reference/update-transactional-email)
|
|
893
|
+
|
|
894
|
+
#### Parameters
|
|
895
|
+
|
|
896
|
+
| Name | Type | Required | Notes |
|
|
897
|
+
| ------------------------ | ------ | -------- | ------------------------------------------------------------ |
|
|
898
|
+
| `transactional_id` | string | Yes | |
|
|
899
|
+
| `name` | string | No | |
|
|
900
|
+
| `transactional_group_id` | string | No | The ID of the group to move this transactional email to. |
|
|
901
|
+
|
|
902
|
+
At least one field must be provided.
|
|
903
|
+
|
|
904
|
+
#### Example
|
|
905
|
+
|
|
906
|
+
```ruby
|
|
907
|
+
response = LoopsSdk::Transactional.update(
|
|
908
|
+
transactional_id: "clfq6dinn000yl70fgwwyp82l",
|
|
909
|
+
name: "Updated name"
|
|
910
|
+
)
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
#### Response
|
|
914
|
+
|
|
915
|
+
```json
|
|
916
|
+
{
|
|
917
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
918
|
+
"name": "Updated name",
|
|
919
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
920
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
921
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
922
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
923
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
924
|
+
"dataVariables": ["confirmationUrl"]
|
|
925
|
+
}
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
---
|
|
929
|
+
|
|
930
|
+
### Transactional.ensure_draft()
|
|
931
|
+
|
|
932
|
+
Ensure a transactional email has a draft email message. If a draft already exists it is returned unchanged; otherwise a new empty draft is created.
|
|
933
|
+
|
|
934
|
+
[API Reference](https://loops.so/docs/api-reference/ensure-transactional-email-draft)
|
|
935
|
+
|
|
936
|
+
#### Parameters
|
|
937
|
+
|
|
938
|
+
| Name | Type | Required | Notes |
|
|
939
|
+
| ------------------ | ------ | -------- | ----- |
|
|
940
|
+
| `transactional_id` | string | Yes | |
|
|
941
|
+
|
|
942
|
+
#### Example
|
|
943
|
+
|
|
944
|
+
```ruby
|
|
945
|
+
response = LoopsSdk::Transactional.ensure_draft(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
#### Response
|
|
949
|
+
|
|
950
|
+
```json
|
|
951
|
+
{
|
|
952
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
953
|
+
"name": "Sign up confirmation",
|
|
954
|
+
"draftEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
955
|
+
"draftEmailMessageContentRevisionId": "clrev1s10n2i3d4e5f6g7h8",
|
|
956
|
+
"publishedEmailMessageId": null,
|
|
957
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
958
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
959
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
960
|
+
"dataVariables": []
|
|
961
|
+
}
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
---
|
|
965
|
+
|
|
966
|
+
### Transactional.publish()
|
|
967
|
+
|
|
968
|
+
Publish a transactional email's current draft. The draft becomes the published version and the draft is cleared.
|
|
969
|
+
|
|
970
|
+
[API Reference](https://loops.so/docs/api-reference/publish-transactional-email)
|
|
971
|
+
|
|
972
|
+
#### Parameters
|
|
973
|
+
|
|
974
|
+
| Name | Type | Required | Notes |
|
|
975
|
+
| ------------------ | ------ | -------- | ----- |
|
|
976
|
+
| `transactional_id` | string | Yes | |
|
|
977
|
+
|
|
978
|
+
#### Example
|
|
979
|
+
|
|
980
|
+
```ruby
|
|
981
|
+
response = LoopsSdk::Transactional.publish(transactional_id: "clfq6dinn000yl70fgwwyp82l")
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
#### Response
|
|
985
|
+
|
|
986
|
+
```json
|
|
987
|
+
{
|
|
988
|
+
"id": "cll42l54f20i1la0lfooe3z12",
|
|
989
|
+
"name": "Sign up confirmation",
|
|
990
|
+
"draftEmailMessageId": null,
|
|
991
|
+
"publishedEmailMessageId": "cle5f7g9h1i3j5k7l9m1n3p5",
|
|
992
|
+
"transactionalGroupId": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
993
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
994
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
995
|
+
"dataVariables": []
|
|
996
|
+
}
|
|
997
|
+
```
|
|
998
|
+
|
|
999
|
+
---
|
|
1000
|
+
|
|
729
1001
|
### Transactional.send()
|
|
730
1002
|
|
|
731
1003
|
Send a transactional email to a contact. [Learn about sending transactional email](https://loops.so/docs/transactional/guide)
|
|
@@ -736,7 +1008,7 @@ Send a transactional email to a contact. [Learn about sending transactional emai
|
|
|
736
1008
|
|
|
737
1009
|
| Name | Type | Required | Notes |
|
|
738
1010
|
| ---------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
739
|
-
| `transactional_id`
|
|
1011
|
+
| `transactional_id` | string | Yes | The ID of the transactional email to send. |
|
|
740
1012
|
| `email` | string | Yes | The email address of the recipient. |
|
|
741
1013
|
| `add_to_audience` | boolean | No | If `true`, a contact will be created in your audience using the `email` value (if a matching contact doesn't already exist). |
|
|
742
1014
|
| `data_variables` | object | No | An object containing data as defined by the data variables added to the transactional email template.<br />Values can be of type `string` or `number`. |
|
|
@@ -819,11 +1091,37 @@ If there is a problem with the request, a descriptive error message will be retu
|
|
|
819
1091
|
|
|
820
1092
|
---
|
|
821
1093
|
|
|
822
|
-
###
|
|
1094
|
+
### DedicatedSendingIps.list()
|
|
823
1095
|
|
|
824
|
-
Get
|
|
1096
|
+
Get Loops' dedicated sending IP addresses.
|
|
825
1097
|
|
|
826
|
-
[API Reference](https://loops.so/docs/api-reference/list-
|
|
1098
|
+
[API Reference](https://loops.so/docs/api-reference/list-dedicated-sending-ips)
|
|
1099
|
+
|
|
1100
|
+
#### Parameters
|
|
1101
|
+
|
|
1102
|
+
None
|
|
1103
|
+
|
|
1104
|
+
#### Example
|
|
1105
|
+
|
|
1106
|
+
```ruby
|
|
1107
|
+
response = LoopsSdk::DedicatedSendingIps.list
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
#### Response
|
|
1111
|
+
|
|
1112
|
+
Returns an array of IP address strings.
|
|
1113
|
+
|
|
1114
|
+
```json
|
|
1115
|
+
["1.2.3.4", "5.6.7.8"]
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
### Themes.list()
|
|
1121
|
+
|
|
1122
|
+
List email themes.
|
|
1123
|
+
|
|
1124
|
+
[API Reference](https://loops.so/docs/api-reference/list-themes)
|
|
827
1125
|
|
|
828
1126
|
#### Parameters
|
|
829
1127
|
|
|
@@ -835,9 +1133,9 @@ Get a list of published transactional emails.
|
|
|
835
1133
|
#### Example
|
|
836
1134
|
|
|
837
1135
|
```ruby
|
|
838
|
-
response = LoopsSdk::
|
|
1136
|
+
response = LoopsSdk::Themes.list
|
|
839
1137
|
|
|
840
|
-
response = LoopsSdk::
|
|
1138
|
+
response = LoopsSdk::Themes.list(perPage: 15, cursor: "cursor_value")
|
|
841
1139
|
```
|
|
842
1140
|
|
|
843
1141
|
#### Response
|
|
@@ -845,107 +1143,138 @@ response = LoopsSdk::Transactional.list(perPage: 15)
|
|
|
845
1143
|
```json
|
|
846
1144
|
{
|
|
847
1145
|
"pagination": {
|
|
848
|
-
"totalResults":
|
|
849
|
-
"returnedResults":
|
|
1146
|
+
"totalResults": 1,
|
|
1147
|
+
"returnedResults": 1,
|
|
850
1148
|
"perPage": 20,
|
|
851
|
-
"totalPages":
|
|
852
|
-
"nextCursor":
|
|
853
|
-
"nextPage":
|
|
1149
|
+
"totalPages": 1,
|
|
1150
|
+
"nextCursor": null,
|
|
1151
|
+
"nextPage": null
|
|
854
1152
|
},
|
|
855
1153
|
"data": [
|
|
856
1154
|
{
|
|
857
|
-
"id": "
|
|
858
|
-
"
|
|
859
|
-
"
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
"
|
|
863
|
-
|
|
864
|
-
"dataVariables": [
|
|
865
|
-
"confirmationUrl"
|
|
866
|
-
]
|
|
867
|
-
},
|
|
868
|
-
{
|
|
869
|
-
"id": "clw6rbuwp01rmeiyndm80155l",
|
|
870
|
-
"lastUpdated": "2024-05-14T19:02:52.000Z",
|
|
871
|
-
"dataVariables": [
|
|
872
|
-
"firstName",
|
|
873
|
-
"lastName",
|
|
874
|
-
"inviteLink"
|
|
875
|
-
]
|
|
876
|
-
},
|
|
877
|
-
...
|
|
1155
|
+
"id": "clo1z5q7s004yl70y3z4a5b6c",
|
|
1156
|
+
"name": "Default",
|
|
1157
|
+
"styles": { "backgroundColor": "#ffffff" },
|
|
1158
|
+
"isDefault": true,
|
|
1159
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1160
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1161
|
+
}
|
|
878
1162
|
]
|
|
879
1163
|
}
|
|
880
1164
|
```
|
|
881
1165
|
|
|
882
1166
|
---
|
|
883
1167
|
|
|
884
|
-
###
|
|
1168
|
+
### Themes.get()
|
|
885
1169
|
|
|
886
|
-
Get
|
|
1170
|
+
Get a single theme by ID.
|
|
887
1171
|
|
|
888
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
1172
|
+
[API Reference](https://loops.so/docs/api-reference/get-theme)
|
|
889
1173
|
|
|
890
1174
|
#### Parameters
|
|
891
1175
|
|
|
892
|
-
|
|
1176
|
+
| Name | Type | Required | Notes |
|
|
1177
|
+
| ---------- | ------ | -------- | ----- |
|
|
1178
|
+
| `theme_id` | string | Yes | |
|
|
893
1179
|
|
|
894
1180
|
#### Example
|
|
895
1181
|
|
|
896
1182
|
```ruby
|
|
897
|
-
response = LoopsSdk::
|
|
1183
|
+
response = LoopsSdk::Themes.get(theme_id: "clo5p8q0r0132ntx6flkunw89")
|
|
898
1184
|
```
|
|
899
1185
|
|
|
900
1186
|
#### Response
|
|
901
1187
|
|
|
902
|
-
Returns an array of IP address strings.
|
|
903
|
-
|
|
904
1188
|
```json
|
|
905
|
-
|
|
1189
|
+
{
|
|
1190
|
+
"id": "clo1z5q7s004yl70y3z4a5b6c",
|
|
1191
|
+
"name": "Default",
|
|
1192
|
+
"styles": { "backgroundColor": "#ffffff" },
|
|
1193
|
+
"isDefault": true,
|
|
1194
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1195
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1196
|
+
}
|
|
906
1197
|
```
|
|
907
1198
|
|
|
908
1199
|
---
|
|
909
1200
|
|
|
910
|
-
### Themes.
|
|
1201
|
+
### Themes.create()
|
|
911
1202
|
|
|
912
|
-
|
|
1203
|
+
Create a new email theme.
|
|
913
1204
|
|
|
914
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
1205
|
+
[API Reference](https://loops.so/docs/api-reference/create-theme)
|
|
915
1206
|
|
|
916
1207
|
#### Parameters
|
|
917
1208
|
|
|
918
|
-
| Name
|
|
919
|
-
|
|
|
920
|
-
| `
|
|
921
|
-
| `
|
|
1209
|
+
| Name | Type | Required | Notes |
|
|
1210
|
+
| -------- | ------ | -------- | -------------------------------------------------------------------------------------------------- |
|
|
1211
|
+
| `name` | string | Yes | |
|
|
1212
|
+
| `styles` | object | No | Style attributes matching LMX `<Style />` tag attribute names. See the API reference for the full list. |
|
|
922
1213
|
|
|
923
1214
|
#### Example
|
|
924
1215
|
|
|
925
1216
|
```ruby
|
|
926
|
-
response = LoopsSdk::Themes.
|
|
1217
|
+
response = LoopsSdk::Themes.create(
|
|
1218
|
+
name: "Dark mode",
|
|
1219
|
+
styles: { backgroundColor: "#111827", bodyColor: "#1f2937" }
|
|
1220
|
+
)
|
|
1221
|
+
```
|
|
927
1222
|
|
|
928
|
-
|
|
1223
|
+
#### Response
|
|
1224
|
+
|
|
1225
|
+
```json
|
|
1226
|
+
{
|
|
1227
|
+
"id": "clt3u5v7w9x1y3z5a7b9c1d3",
|
|
1228
|
+
"name": "Dark mode",
|
|
1229
|
+
"styles": {
|
|
1230
|
+
"backgroundColor": "#111827",
|
|
1231
|
+
"bodyColor": "#1f2937"
|
|
1232
|
+
},
|
|
1233
|
+
"isDefault": false,
|
|
1234
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1235
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1236
|
+
}
|
|
929
1237
|
```
|
|
930
1238
|
|
|
931
1239
|
---
|
|
932
1240
|
|
|
933
|
-
### Themes.
|
|
1241
|
+
### Themes.update()
|
|
934
1242
|
|
|
935
|
-
|
|
1243
|
+
Update a theme's name and/or styles. Style changes cascade to emails using the theme.
|
|
936
1244
|
|
|
937
|
-
[API Reference](https://loops.so/docs/api-reference/
|
|
1245
|
+
[API Reference](https://loops.so/docs/api-reference/update-theme)
|
|
938
1246
|
|
|
939
1247
|
#### Parameters
|
|
940
1248
|
|
|
941
1249
|
| Name | Type | Required | Notes |
|
|
942
1250
|
| ---------- | ------ | -------- | ----- |
|
|
943
1251
|
| `theme_id` | string | Yes | |
|
|
1252
|
+
| `name` | string | No | |
|
|
1253
|
+
| `styles` | object | No | |
|
|
1254
|
+
|
|
1255
|
+
At least one of `name` or `styles` must be provided.
|
|
944
1256
|
|
|
945
1257
|
#### Example
|
|
946
1258
|
|
|
947
1259
|
```ruby
|
|
948
|
-
response = LoopsSdk::Themes.
|
|
1260
|
+
response = LoopsSdk::Themes.update(
|
|
1261
|
+
theme_id: "clo5p8q0r0132ntx6flkunw89",
|
|
1262
|
+
name: "Updated theme"
|
|
1263
|
+
)
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
#### Response
|
|
1267
|
+
|
|
1268
|
+
```json
|
|
1269
|
+
{
|
|
1270
|
+
"id": "clt3u5v7w9x1y3z5a7b9c1d3",
|
|
1271
|
+
"name": "Updated theme",
|
|
1272
|
+
"styles": { "backgroundColor": "#111827" },
|
|
1273
|
+
"isDefault": false,
|
|
1274
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1275
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
1276
|
+
"affectedEmailCount": 3
|
|
1277
|
+
}
|
|
949
1278
|
```
|
|
950
1279
|
|
|
951
1280
|
---
|
|
@@ -969,6 +1298,28 @@ List email components.
|
|
|
969
1298
|
response = LoopsSdk::Components.list
|
|
970
1299
|
```
|
|
971
1300
|
|
|
1301
|
+
#### Response
|
|
1302
|
+
|
|
1303
|
+
```json
|
|
1304
|
+
{
|
|
1305
|
+
"pagination": {
|
|
1306
|
+
"totalResults": 1,
|
|
1307
|
+
"returnedResults": 1,
|
|
1308
|
+
"perPage": 20,
|
|
1309
|
+
"totalPages": 1,
|
|
1310
|
+
"nextCursor": null,
|
|
1311
|
+
"nextPage": null
|
|
1312
|
+
},
|
|
1313
|
+
"data": [
|
|
1314
|
+
{
|
|
1315
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1316
|
+
"name": "Header",
|
|
1317
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1318
|
+
}
|
|
1319
|
+
]
|
|
1320
|
+
}
|
|
1321
|
+
```
|
|
1322
|
+
|
|
972
1323
|
---
|
|
973
1324
|
|
|
974
1325
|
### Components.get()
|
|
@@ -981,19 +1332,101 @@ Get a single component by ID.
|
|
|
981
1332
|
|
|
982
1333
|
| Name | Type | Required | Notes |
|
|
983
1334
|
| -------------- | ------ | -------- | ----- |
|
|
984
|
-
| `component_id`
|
|
1335
|
+
| `component_id` | string | Yes | |
|
|
985
1336
|
|
|
986
1337
|
#### Example
|
|
987
1338
|
|
|
988
1339
|
```ruby
|
|
989
|
-
response = LoopsSdk::Components.get(component_id: "
|
|
1340
|
+
response = LoopsSdk::Components.get(component_id: "clp6q9r1s0154ouy7gmlovx90")
|
|
990
1341
|
```
|
|
991
1342
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1343
|
+
#### Response
|
|
1344
|
+
|
|
1345
|
+
```json
|
|
1346
|
+
{
|
|
1347
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1348
|
+
"name": "Header",
|
|
1349
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1350
|
+
}
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
---
|
|
1354
|
+
|
|
1355
|
+
### Components.create()
|
|
1356
|
+
|
|
1357
|
+
Create a new email component from an LMX body.
|
|
1358
|
+
|
|
1359
|
+
[API Reference](https://loops.so/docs/api-reference/create-component)
|
|
1360
|
+
|
|
1361
|
+
#### Parameters
|
|
1362
|
+
|
|
1363
|
+
| Name | Type | Required | Notes |
|
|
1364
|
+
| ------ | ------ | -------- | -------------------------------- |
|
|
1365
|
+
| `name` | string | Yes | |
|
|
1366
|
+
| `lmx` | string | Yes | The component body as LMX. |
|
|
1367
|
+
|
|
1368
|
+
#### Example
|
|
1369
|
+
|
|
1370
|
+
```ruby
|
|
1371
|
+
response = LoopsSdk::Components.create(
|
|
1372
|
+
name: "Header",
|
|
1373
|
+
lmx: "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1374
|
+
)
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
#### Response
|
|
1378
|
+
|
|
1379
|
+
```json
|
|
1380
|
+
{
|
|
1381
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1382
|
+
"name": "Header",
|
|
1383
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>"
|
|
1384
|
+
}
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
---
|
|
1388
|
+
|
|
1389
|
+
### Components.update()
|
|
1390
|
+
|
|
1391
|
+
Update a component's name and/or LMX body. Body changes cascade to emails using the component.
|
|
1392
|
+
|
|
1393
|
+
[API Reference](https://loops.so/docs/api-reference/update-component)
|
|
1394
|
+
|
|
1395
|
+
#### Parameters
|
|
1396
|
+
|
|
1397
|
+
| Name | Type | Required | Notes |
|
|
1398
|
+
| -------------- | ------ | -------- | ----- |
|
|
1399
|
+
| `component_id` | string | Yes | |
|
|
1400
|
+
| `name` | string | No | |
|
|
1401
|
+
| `lmx` | string | No | |
|
|
1402
|
+
|
|
1403
|
+
At least one of `name` or `lmx` must be provided.
|
|
1404
|
+
|
|
1405
|
+
#### Example
|
|
1406
|
+
|
|
1407
|
+
```ruby
|
|
1408
|
+
response = LoopsSdk::Components.update(
|
|
1409
|
+
component_id: "clp6q9r1s0154ouy7gmlovx90",
|
|
1410
|
+
name: "Updated Header"
|
|
1411
|
+
)
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
#### Response
|
|
1415
|
+
|
|
1416
|
+
```json
|
|
1417
|
+
{
|
|
1418
|
+
"id": "clp2a6r8t005yl70d7e8f9g0h",
|
|
1419
|
+
"name": "Updated Header",
|
|
1420
|
+
"lmx": "<Paragraph>Welcome to Acme</Paragraph>",
|
|
1421
|
+
"affectedEmailCount": 2
|
|
1422
|
+
}
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
---
|
|
1426
|
+
|
|
1427
|
+
### Campaigns.list()
|
|
1428
|
+
|
|
1429
|
+
List campaigns.
|
|
997
1430
|
|
|
998
1431
|
[API Reference](https://loops.so/docs/api-reference/list-campaigns)
|
|
999
1432
|
|
|
@@ -1010,6 +1443,36 @@ List campaigns.
|
|
|
1010
1443
|
response = LoopsSdk::Campaigns.list
|
|
1011
1444
|
```
|
|
1012
1445
|
|
|
1446
|
+
#### Response
|
|
1447
|
+
|
|
1448
|
+
```json
|
|
1449
|
+
{
|
|
1450
|
+
"pagination": {
|
|
1451
|
+
"totalResults": 1,
|
|
1452
|
+
"returnedResults": 1,
|
|
1453
|
+
"perPage": 20,
|
|
1454
|
+
"totalPages": 1,
|
|
1455
|
+
"nextCursor": null,
|
|
1456
|
+
"nextPage": null
|
|
1457
|
+
},
|
|
1458
|
+
"data": [
|
|
1459
|
+
{
|
|
1460
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1461
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1462
|
+
"name": "Spring announcement",
|
|
1463
|
+
"status": "Draft",
|
|
1464
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1465
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1466
|
+
"campaignGroupId": null,
|
|
1467
|
+
"mailingListId": null,
|
|
1468
|
+
"audienceSegmentId": null,
|
|
1469
|
+
"audienceFilter": null,
|
|
1470
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1471
|
+
}
|
|
1472
|
+
]
|
|
1473
|
+
}
|
|
1474
|
+
```
|
|
1475
|
+
|
|
1013
1476
|
---
|
|
1014
1477
|
|
|
1015
1478
|
### Campaigns.create()
|
|
@@ -1020,14 +1483,44 @@ Create a draft campaign. An empty email message is created automatically.
|
|
|
1020
1483
|
|
|
1021
1484
|
#### Parameters
|
|
1022
1485
|
|
|
1023
|
-
| Name
|
|
1024
|
-
|
|
|
1025
|
-
| `name`
|
|
1486
|
+
| Name | Type | Required | Notes |
|
|
1487
|
+
| ---------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- |
|
|
1488
|
+
| `name` | string | Yes | |
|
|
1489
|
+
| `campaign_group_id` | string | No | The ID of the group to add this campaign to. |
|
|
1490
|
+
| `mailing_list_id` | string | No | The ID of the mailing list to send to. |
|
|
1491
|
+
| `audience_segment_id` | string | No | The ID of an audience segment. Setting this clears any `audience_filter`. |
|
|
1492
|
+
| `audience_filter` | object | No | A tree of audience conditions. See the API reference for the filter schema. |
|
|
1493
|
+
| `scheduling` | object | No | When the campaign should send. Use `{ method: "now" }` or `{ method: "schedule", timestamp: "..." }`. |
|
|
1026
1494
|
|
|
1027
1495
|
#### Example
|
|
1028
1496
|
|
|
1029
1497
|
```ruby
|
|
1030
1498
|
response = LoopsSdk::Campaigns.create(name: "Spring announcement")
|
|
1499
|
+
|
|
1500
|
+
response = LoopsSdk::Campaigns.create(
|
|
1501
|
+
name: "Spring announcement",
|
|
1502
|
+
mailing_list_id: "cm06f5v0e45nf0ml5754o9cix",
|
|
1503
|
+
scheduling: { method: "schedule", timestamp: "2026-06-01T10:00:00Z" }
|
|
1504
|
+
)
|
|
1505
|
+
```
|
|
1506
|
+
|
|
1507
|
+
#### Response
|
|
1508
|
+
|
|
1509
|
+
```json
|
|
1510
|
+
{
|
|
1511
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1512
|
+
"name": "Spring announcement",
|
|
1513
|
+
"status": "Draft",
|
|
1514
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1515
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1516
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1517
|
+
"emailMessageContentRevisionId": "clv8g2x4z012yl70n5o6p7q8r",
|
|
1518
|
+
"campaignGroupId": null,
|
|
1519
|
+
"mailingListId": null,
|
|
1520
|
+
"audienceSegmentId": null,
|
|
1521
|
+
"audienceFilter": null,
|
|
1522
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1523
|
+
}
|
|
1031
1524
|
```
|
|
1032
1525
|
|
|
1033
1526
|
---
|
|
@@ -1042,38 +1535,81 @@ Get a single campaign by ID.
|
|
|
1042
1535
|
|
|
1043
1536
|
| Name | Type | Required | Notes |
|
|
1044
1537
|
| ------------- | ------ | -------- | ----- |
|
|
1045
|
-
| `campaign_id`
|
|
1538
|
+
| `campaign_id` | string | Yes | |
|
|
1046
1539
|
|
|
1047
1540
|
#### Example
|
|
1048
1541
|
|
|
1049
1542
|
```ruby
|
|
1050
|
-
response = LoopsSdk::Campaigns.get(campaign_id: "
|
|
1543
|
+
response = LoopsSdk::Campaigns.get(campaign_id: "cln4o7p9q0110msw5ekjtmv78")
|
|
1544
|
+
```
|
|
1545
|
+
|
|
1546
|
+
#### Response
|
|
1547
|
+
|
|
1548
|
+
```json
|
|
1549
|
+
{
|
|
1550
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1551
|
+
"name": "Spring announcement",
|
|
1552
|
+
"status": "Draft",
|
|
1553
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1554
|
+
"updatedAt": "2025-01-01T00:00:00.000Z",
|
|
1555
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1556
|
+
"campaignGroupId": null,
|
|
1557
|
+
"mailingListId": null,
|
|
1558
|
+
"audienceSegmentId": null,
|
|
1559
|
+
"audienceFilter": null,
|
|
1560
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1561
|
+
}
|
|
1051
1562
|
```
|
|
1052
1563
|
|
|
1053
1564
|
---
|
|
1054
1565
|
|
|
1055
1566
|
### Campaigns.update()
|
|
1056
1567
|
|
|
1057
|
-
Update a draft campaign's name.
|
|
1568
|
+
Update a draft campaign's name, group, audience, or scheduling.
|
|
1058
1569
|
|
|
1059
1570
|
[API Reference](https://loops.so/docs/api-reference/update-campaign)
|
|
1060
1571
|
|
|
1061
1572
|
#### Parameters
|
|
1062
1573
|
|
|
1063
|
-
| Name
|
|
1064
|
-
|
|
|
1065
|
-
| `campaign_id`
|
|
1066
|
-
| `name`
|
|
1574
|
+
| Name | Type | Required | Notes |
|
|
1575
|
+
| --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- |
|
|
1576
|
+
| `campaign_id` | string | Yes | |
|
|
1577
|
+
| `name` | string | No | |
|
|
1578
|
+
| `campaign_group_id` | string | No | The ID of the group to move this campaign to. |
|
|
1579
|
+
| `mailing_list_id` | string | No | The ID of the mailing list to send to. |
|
|
1580
|
+
| `audience_segment_id` | string | No | The ID of an audience segment. Setting this clears any `audience_filter`. |
|
|
1581
|
+
| `audience_filter` | object | No | A tree of audience conditions. See the API reference for the filter schema. |
|
|
1582
|
+
| `scheduling` | object | No | When the campaign should send. Use `{ method: "now" }` or `{ method: "schedule", timestamp: "..." }`. |
|
|
1583
|
+
|
|
1584
|
+
At least one field must be provided.
|
|
1067
1585
|
|
|
1068
1586
|
#### Example
|
|
1069
1587
|
|
|
1070
1588
|
```ruby
|
|
1071
1589
|
response = LoopsSdk::Campaigns.update(
|
|
1072
|
-
campaign_id: "
|
|
1590
|
+
campaign_id: "cln4o7p9q0110msw5ekjtmv78",
|
|
1073
1591
|
name: "Updated campaign name"
|
|
1074
1592
|
)
|
|
1075
1593
|
```
|
|
1076
1594
|
|
|
1595
|
+
#### Response
|
|
1596
|
+
|
|
1597
|
+
```json
|
|
1598
|
+
{
|
|
1599
|
+
"id": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1600
|
+
"name": "Updated campaign name",
|
|
1601
|
+
"status": "Draft",
|
|
1602
|
+
"createdAt": "2025-01-01T00:00:00.000Z",
|
|
1603
|
+
"updatedAt": "2025-01-02T00:00:00.000Z",
|
|
1604
|
+
"emailMessageId": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1605
|
+
"campaignGroupId": null,
|
|
1606
|
+
"mailingListId": null,
|
|
1607
|
+
"audienceSegmentId": null,
|
|
1608
|
+
"audienceFilter": null,
|
|
1609
|
+
"scheduling": { "method": "now", "timestamp": null }
|
|
1610
|
+
}
|
|
1611
|
+
```
|
|
1612
|
+
|
|
1077
1613
|
---
|
|
1078
1614
|
|
|
1079
1615
|
### EmailMessages.get()
|
|
@@ -1086,12 +1622,30 @@ Get an email message, including its LMX content.
|
|
|
1086
1622
|
|
|
1087
1623
|
| Name | Type | Required | Notes |
|
|
1088
1624
|
| ------------------- | ------ | -------- | ----- |
|
|
1089
|
-
| `email_message_id`
|
|
1625
|
+
| `email_message_id` | string | Yes | |
|
|
1090
1626
|
|
|
1091
1627
|
#### Example
|
|
1092
1628
|
|
|
1093
1629
|
```ruby
|
|
1094
|
-
response = LoopsSdk::EmailMessages.get(email_message_id: "
|
|
1630
|
+
response = LoopsSdk::EmailMessages.get(email_message_id: "cly8k3m0n0044jpx2bghepq45")
|
|
1631
|
+
```
|
|
1632
|
+
|
|
1633
|
+
#### Response
|
|
1634
|
+
|
|
1635
|
+
```json
|
|
1636
|
+
{
|
|
1637
|
+
"id": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1638
|
+
"campaignId": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1639
|
+
"subject": "Hello",
|
|
1640
|
+
"previewText": "Preview text",
|
|
1641
|
+
"fromName": "Loops",
|
|
1642
|
+
"fromEmail": "hello",
|
|
1643
|
+
"replyToEmail": "",
|
|
1644
|
+
"emailFormat": "styled",
|
|
1645
|
+
"lmx": "<H1>...</H1><Paragraph>...</Paragraph>",
|
|
1646
|
+
"contentRevisionId": "clv8g2x4z012yl70n5o6p7q8r",
|
|
1647
|
+
"updatedAt": "2025-01-01T00:00:00.000Z"
|
|
1648
|
+
}
|
|
1095
1649
|
```
|
|
1096
1650
|
|
|
1097
1651
|
---
|
|
@@ -1104,31 +1658,1226 @@ Update an email message for a draft campaign.
|
|
|
1104
1658
|
|
|
1105
1659
|
#### Parameters
|
|
1106
1660
|
|
|
1107
|
-
| Name
|
|
1108
|
-
|
|
|
1109
|
-
| `email_message_id`
|
|
1110
|
-
| `expected_revision_id`
|
|
1111
|
-
| `subject`
|
|
1112
|
-
| `preview_text`
|
|
1113
|
-
| `from_name`
|
|
1114
|
-
| `from_email`
|
|
1115
|
-
| `reply_to_email`
|
|
1116
|
-
| `
|
|
1661
|
+
| Name | Type | Required | Notes |
|
|
1662
|
+
| ------------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
|
|
1663
|
+
| `email_message_id` | string | Yes | |
|
|
1664
|
+
| `expected_revision_id` | string | No | The `contentRevisionId` from your last fetch. Required to avoid stale concurrent updates. |
|
|
1665
|
+
| `subject` | string | No | |
|
|
1666
|
+
| `preview_text` | string | No | |
|
|
1667
|
+
| `from_name` | string | No | |
|
|
1668
|
+
| `from_email` | string | No | Sender username without `@` or domain. The team's sending domain is appended automatically. |
|
|
1669
|
+
| `reply_to_email` | string | No | Must be empty or a valid email address. |
|
|
1670
|
+
| `cc_email` | string | No | CC email address. Requires the team to have CC/BCC enabled. |
|
|
1671
|
+
| `bcc_email` | string | No | BCC email address. Requires the team to have CC/BCC enabled. |
|
|
1672
|
+
| `language_code` | string | No | Language code for the email. Requires translation to be enabled for the team. |
|
|
1673
|
+
| `email_format` | string | No | The rendering format of the email. One of `styled` or `plain`. |
|
|
1674
|
+
| `lmx` | string | No | Email body serialized as LMX. Styles must be embedded in the LMX `<Style />` tag. |
|
|
1675
|
+
| `contact_properties_fallbacks` | object | No | Fallback values for contact properties. A null value deletes the fallback. |
|
|
1676
|
+
| `event_properties_fallbacks` | object | No | Fallback values for event properties. A null value deletes the fallback. |
|
|
1677
|
+
| `data_variables_fallbacks` | object | No | Fallback values for data variables. A null value deletes the fallback. |
|
|
1117
1678
|
|
|
1118
1679
|
#### Example
|
|
1119
1680
|
|
|
1120
1681
|
```ruby
|
|
1121
1682
|
response = LoopsSdk::EmailMessages.update(
|
|
1122
|
-
email_message_id: "
|
|
1123
|
-
expected_revision_id: "
|
|
1683
|
+
email_message_id: "cly8k3m0n0044jpx2bghepq45",
|
|
1684
|
+
expected_revision_id: "clm9n4o6p0088lrz4dijslt67",
|
|
1124
1685
|
subject: "Spring announcement",
|
|
1125
1686
|
preview_text: "See what's new",
|
|
1126
1687
|
from_name: "Loops",
|
|
1127
1688
|
from_email: "hello",
|
|
1128
|
-
lmx: "<
|
|
1689
|
+
lmx: "<Style /><Paragraph>...</Paragraph>"
|
|
1690
|
+
)
|
|
1691
|
+
```
|
|
1692
|
+
|
|
1693
|
+
#### Response
|
|
1694
|
+
|
|
1695
|
+
```json
|
|
1696
|
+
{
|
|
1697
|
+
"id": "clm9x3o5q002yl70a8b3c4d5e",
|
|
1698
|
+
"campaignId": "cln0y4p6r003yl70i1j2k3l4m",
|
|
1699
|
+
"subject": "Spring announcement",
|
|
1700
|
+
"previewText": "See what's new",
|
|
1701
|
+
"fromName": "Loops",
|
|
1702
|
+
"fromEmail": "hello",
|
|
1703
|
+
"replyToEmail": "",
|
|
1704
|
+
"emailFormat": "styled",
|
|
1705
|
+
"lmx": "<Style /><Paragraph>...</Paragraph>",
|
|
1706
|
+
"contentRevisionId": "clv8g2x4z013yl70s9t0u1v2w",
|
|
1707
|
+
"updatedAt": "2025-01-02T00:00:00.000Z"
|
|
1708
|
+
}
|
|
1709
|
+
```
|
|
1710
|
+
|
|
1711
|
+
---
|
|
1712
|
+
|
|
1713
|
+
### EmailMessages.preview()
|
|
1714
|
+
|
|
1715
|
+
Send a test preview of an email message to one or more addresses.
|
|
1716
|
+
|
|
1717
|
+
[API Reference](https://loops.so/docs/api-reference/preview-email-message)
|
|
1718
|
+
|
|
1719
|
+
#### Parameters
|
|
1720
|
+
|
|
1721
|
+
| Name | Type | Required | Notes |
|
|
1722
|
+
| -------------------- | -------- | -------- | --------------------------------------------------------------------------------- |
|
|
1723
|
+
| `email_message_id` | string | Yes | |
|
|
1724
|
+
| `emails` | string[] | Yes | One or more addresses to send the preview to. |
|
|
1725
|
+
| `contact_properties` | object | No | Contact property values to render. Accepted for campaign and workflow previews. |
|
|
1726
|
+
| `event_properties` | object | No | Event property values to render. Accepted for workflow previews only. |
|
|
1727
|
+
| `data_variables` | object | No | Transactional data variables to render. Accepted for transactional previews only. |
|
|
1728
|
+
|
|
1729
|
+
#### Example
|
|
1730
|
+
|
|
1731
|
+
```ruby
|
|
1732
|
+
response = LoopsSdk::EmailMessages.preview(
|
|
1733
|
+
email_message_id: "cly8k3m0n0044jpx2bghepq45",
|
|
1734
|
+
emails: ["test@example.com"],
|
|
1735
|
+
contact_properties: { firstName: "Alex" }
|
|
1736
|
+
)
|
|
1737
|
+
```
|
|
1738
|
+
|
|
1739
|
+
#### Response
|
|
1740
|
+
|
|
1741
|
+
```json
|
|
1742
|
+
{
|
|
1743
|
+
"id": "cle5f7g9h1i3j5k7l9m1n3p5"
|
|
1744
|
+
}
|
|
1745
|
+
```
|
|
1746
|
+
|
|
1747
|
+
---
|
|
1748
|
+
|
|
1749
|
+
### EmailMessages.run_guardian()
|
|
1750
|
+
|
|
1751
|
+
Run Guardian content validation on an email message and return errors and warnings.
|
|
1752
|
+
|
|
1753
|
+
[API Reference](https://loops.so/docs/api-reference/run-guardian-checks)
|
|
1754
|
+
|
|
1755
|
+
#### Parameters
|
|
1756
|
+
|
|
1757
|
+
| Name | Type | Required | Notes |
|
|
1758
|
+
| ------------------ | ------ | -------- | ----- |
|
|
1759
|
+
| `email_message_id` | string | Yes | |
|
|
1760
|
+
|
|
1761
|
+
#### Example
|
|
1762
|
+
|
|
1763
|
+
```ruby
|
|
1764
|
+
response = LoopsSdk::EmailMessages.run_guardian(email_message_id: "cly8k3m0n0044jpx2bghepq45")
|
|
1765
|
+
```
|
|
1766
|
+
|
|
1767
|
+
#### Response
|
|
1768
|
+
|
|
1769
|
+
```json
|
|
1770
|
+
{
|
|
1771
|
+
"errors": [
|
|
1772
|
+
{
|
|
1773
|
+
"rule": "missingButtonHrefs",
|
|
1774
|
+
"title": "Missing button link",
|
|
1775
|
+
"description": "Buttons won't work without href value",
|
|
1776
|
+
"items": [{ "label": "Click here" }]
|
|
1777
|
+
}
|
|
1778
|
+
],
|
|
1779
|
+
"warnings": []
|
|
1780
|
+
}
|
|
1781
|
+
```
|
|
1782
|
+
|
|
1783
|
+
---
|
|
1784
|
+
|
|
1785
|
+
### CampaignGroups.list()
|
|
1786
|
+
|
|
1787
|
+
List campaign groups.
|
|
1788
|
+
|
|
1789
|
+
[API Reference](https://loops.so/docs/api-reference/list-campaign-groups)
|
|
1790
|
+
|
|
1791
|
+
#### Parameters
|
|
1792
|
+
|
|
1793
|
+
| Name | Type | Required | Notes |
|
|
1794
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
1795
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
1796
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
1797
|
+
|
|
1798
|
+
#### Example
|
|
1799
|
+
|
|
1800
|
+
```ruby
|
|
1801
|
+
response = LoopsSdk::CampaignGroups.list
|
|
1802
|
+
```
|
|
1803
|
+
|
|
1804
|
+
#### Response
|
|
1805
|
+
|
|
1806
|
+
```json
|
|
1807
|
+
{
|
|
1808
|
+
"pagination": {
|
|
1809
|
+
"totalResults": 1,
|
|
1810
|
+
"returnedResults": 1,
|
|
1811
|
+
"perPage": 20,
|
|
1812
|
+
"totalPages": 1,
|
|
1813
|
+
"nextCursor": null,
|
|
1814
|
+
"nextPage": null
|
|
1815
|
+
},
|
|
1816
|
+
"data": [
|
|
1817
|
+
{
|
|
1818
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1819
|
+
"name": "Newsletters",
|
|
1820
|
+
"description": "Monthly product updates",
|
|
1821
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1822
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1823
|
+
}
|
|
1824
|
+
]
|
|
1825
|
+
}
|
|
1826
|
+
```
|
|
1827
|
+
|
|
1828
|
+
---
|
|
1829
|
+
|
|
1830
|
+
### CampaignGroups.create()
|
|
1831
|
+
|
|
1832
|
+
Create a campaign group.
|
|
1833
|
+
|
|
1834
|
+
[API Reference](https://loops.so/docs/api-reference/create-campaign-group)
|
|
1835
|
+
|
|
1836
|
+
#### Parameters
|
|
1837
|
+
|
|
1838
|
+
| Name | Type | Required | Notes |
|
|
1839
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
1840
|
+
| `name` | string | Yes | Cannot be the reserved name "Unsorted". |
|
|
1841
|
+
| `description` | string | No | An optional description for the group. |
|
|
1842
|
+
|
|
1843
|
+
#### Example
|
|
1844
|
+
|
|
1845
|
+
```ruby
|
|
1846
|
+
response = LoopsSdk::CampaignGroups.create(name: "Newsletters", description: "Monthly updates")
|
|
1847
|
+
```
|
|
1848
|
+
|
|
1849
|
+
#### Response
|
|
1850
|
+
|
|
1851
|
+
```json
|
|
1852
|
+
{
|
|
1853
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1854
|
+
"name": "Newsletters",
|
|
1855
|
+
"description": "Monthly updates",
|
|
1856
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1857
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1858
|
+
}
|
|
1859
|
+
```
|
|
1860
|
+
|
|
1861
|
+
---
|
|
1862
|
+
|
|
1863
|
+
### CampaignGroups.get()
|
|
1864
|
+
|
|
1865
|
+
Get a campaign group by ID.
|
|
1866
|
+
|
|
1867
|
+
[API Reference](https://loops.so/docs/api-reference/get-campaign-group)
|
|
1868
|
+
|
|
1869
|
+
#### Parameters
|
|
1870
|
+
|
|
1871
|
+
| Name | Type | Required | Notes |
|
|
1872
|
+
| ---- | ------ | -------- | ----- |
|
|
1873
|
+
| `campaign_group_id` | string | Yes | |
|
|
1874
|
+
|
|
1875
|
+
#### Example
|
|
1876
|
+
|
|
1877
|
+
```ruby
|
|
1878
|
+
response = LoopsSdk::CampaignGroups.get(campaign_group_id: "clq7r0s2t0176pvz8hnmpwy01")
|
|
1879
|
+
```
|
|
1880
|
+
|
|
1881
|
+
#### Response
|
|
1882
|
+
|
|
1883
|
+
```json
|
|
1884
|
+
{
|
|
1885
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1886
|
+
"name": "Newsletters",
|
|
1887
|
+
"description": "Monthly product updates",
|
|
1888
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1889
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1890
|
+
}
|
|
1891
|
+
```
|
|
1892
|
+
|
|
1893
|
+
---
|
|
1894
|
+
|
|
1895
|
+
### CampaignGroups.update()
|
|
1896
|
+
|
|
1897
|
+
Update a campaign group's name or description.
|
|
1898
|
+
|
|
1899
|
+
[API Reference](https://loops.so/docs/api-reference/update-campaign-group)
|
|
1900
|
+
|
|
1901
|
+
#### Parameters
|
|
1902
|
+
|
|
1903
|
+
| Name | Type | Required | Notes |
|
|
1904
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
1905
|
+
| `campaign_group_id` | string | Yes | |
|
|
1906
|
+
| `name` | string | No | Cannot be the reserved name "Unsorted". |
|
|
1907
|
+
| `description` | string | No | |
|
|
1908
|
+
|
|
1909
|
+
At least one field must be provided.
|
|
1910
|
+
|
|
1911
|
+
#### Example
|
|
1912
|
+
|
|
1913
|
+
```ruby
|
|
1914
|
+
response = LoopsSdk::CampaignGroups.update(
|
|
1915
|
+
campaign_group_id: "clq7r0s2t0176pvz8hnmpwy01",
|
|
1916
|
+
name: "Updated name"
|
|
1129
1917
|
)
|
|
1130
1918
|
```
|
|
1131
1919
|
|
|
1920
|
+
#### Response
|
|
1921
|
+
|
|
1922
|
+
```json
|
|
1923
|
+
{
|
|
1924
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
1925
|
+
"name": "Updated name",
|
|
1926
|
+
"description": "Monthly product updates",
|
|
1927
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1928
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
1929
|
+
}
|
|
1930
|
+
```
|
|
1931
|
+
|
|
1932
|
+
---
|
|
1933
|
+
|
|
1934
|
+
### AudienceSegments.list()
|
|
1935
|
+
|
|
1936
|
+
List audience segments.
|
|
1937
|
+
|
|
1938
|
+
[API Reference](https://loops.so/docs/api-reference/list-audience-segments)
|
|
1939
|
+
|
|
1940
|
+
#### Parameters
|
|
1941
|
+
|
|
1942
|
+
| Name | Type | Required | Notes |
|
|
1943
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
1944
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
1945
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
1946
|
+
|
|
1947
|
+
#### Example
|
|
1948
|
+
|
|
1949
|
+
```ruby
|
|
1950
|
+
response = LoopsSdk::AudienceSegments.list
|
|
1951
|
+
```
|
|
1952
|
+
|
|
1953
|
+
#### Response
|
|
1954
|
+
|
|
1955
|
+
```json
|
|
1956
|
+
{
|
|
1957
|
+
"pagination": {
|
|
1958
|
+
"totalResults": 1,
|
|
1959
|
+
"returnedResults": 1,
|
|
1960
|
+
"perPage": 20,
|
|
1961
|
+
"totalPages": 1,
|
|
1962
|
+
"nextCursor": null,
|
|
1963
|
+
"nextPage": null
|
|
1964
|
+
},
|
|
1965
|
+
"data": [
|
|
1966
|
+
{
|
|
1967
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
1968
|
+
"name": "Power users",
|
|
1969
|
+
"description": "Contacts on the pro plan",
|
|
1970
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
1971
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
1972
|
+
"filter": {
|
|
1973
|
+
"match": "all",
|
|
1974
|
+
"conditions": [
|
|
1975
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
1976
|
+
]
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
]
|
|
1980
|
+
}
|
|
1981
|
+
```
|
|
1982
|
+
|
|
1983
|
+
---
|
|
1984
|
+
|
|
1985
|
+
### AudienceSegments.get()
|
|
1986
|
+
|
|
1987
|
+
Get an audience segment by ID.
|
|
1988
|
+
|
|
1989
|
+
[API Reference](https://loops.so/docs/api-reference/get-audience-segment)
|
|
1990
|
+
|
|
1991
|
+
#### Parameters
|
|
1992
|
+
|
|
1993
|
+
| Name | Type | Required | Notes |
|
|
1994
|
+
| ---- | ------ | -------- | ----- |
|
|
1995
|
+
| `audience_segment_id` | string | Yes | |
|
|
1996
|
+
|
|
1997
|
+
#### Example
|
|
1998
|
+
|
|
1999
|
+
```ruby
|
|
2000
|
+
response = LoopsSdk::AudienceSegments.get(audience_segment_id: "clr8s1t3u0198qw09iotqzx12")
|
|
2001
|
+
```
|
|
2002
|
+
|
|
2003
|
+
#### Response
|
|
2004
|
+
|
|
2005
|
+
```json
|
|
2006
|
+
{
|
|
2007
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
2008
|
+
"name": "Power users",
|
|
2009
|
+
"description": "Contacts on the pro plan",
|
|
2010
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2011
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
2012
|
+
"filter": {
|
|
2013
|
+
"match": "all",
|
|
2014
|
+
"conditions": [
|
|
2015
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
2016
|
+
]
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
```
|
|
2020
|
+
|
|
2021
|
+
---
|
|
2022
|
+
|
|
2023
|
+
### AudienceSegments.create()
|
|
2024
|
+
|
|
2025
|
+
Create a new audience segment.
|
|
2026
|
+
|
|
2027
|
+
[API Reference](https://loops.so/docs/api-reference/create-audience-segment)
|
|
2028
|
+
|
|
2029
|
+
#### Parameters
|
|
2030
|
+
|
|
2031
|
+
| Name | Type | Required | Notes |
|
|
2032
|
+
| ------------- | ------ | -------- | --------------------------------------------------------------------------- |
|
|
2033
|
+
| `name` | string | Yes | Must be unique within the team. |
|
|
2034
|
+
| `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). |
|
|
2035
|
+
| `description` | string | No | |
|
|
2036
|
+
|
|
2037
|
+
#### Example
|
|
2038
|
+
|
|
2039
|
+
```ruby
|
|
2040
|
+
response = LoopsSdk::AudienceSegments.create(
|
|
2041
|
+
name: "Power users",
|
|
2042
|
+
filter: {
|
|
2043
|
+
match: "all",
|
|
2044
|
+
conditions: [
|
|
2045
|
+
{ type: "property", key: "plan", operator: "equals", value: "pro" }
|
|
2046
|
+
]
|
|
2047
|
+
}
|
|
2048
|
+
)
|
|
2049
|
+
```
|
|
2050
|
+
|
|
2051
|
+
#### Response
|
|
2052
|
+
|
|
2053
|
+
```json
|
|
2054
|
+
{
|
|
2055
|
+
"id": "cls6e8g0i2k4m6o8q0s2u4w6",
|
|
2056
|
+
"name": "Power users",
|
|
2057
|
+
"description": null,
|
|
2058
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2059
|
+
"updatedAt": "2025-06-29T07:47:39.370Z",
|
|
2060
|
+
"filter": {
|
|
2061
|
+
"match": "all",
|
|
2062
|
+
"conditions": [
|
|
2063
|
+
{ "type": "property", "key": "plan", "operator": "equals", "value": "pro" }
|
|
2064
|
+
]
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
```
|
|
2068
|
+
|
|
2069
|
+
---
|
|
2070
|
+
|
|
2071
|
+
### Workflows.list()
|
|
2072
|
+
|
|
2073
|
+
List workflows.
|
|
2074
|
+
|
|
2075
|
+
[API Reference](https://loops.so/docs/api-reference/list-workflows)
|
|
2076
|
+
|
|
2077
|
+
#### Parameters
|
|
2078
|
+
|
|
2079
|
+
| Name | Type | Required | Notes |
|
|
2080
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2081
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2082
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2083
|
+
|
|
2084
|
+
#### Example
|
|
2085
|
+
|
|
2086
|
+
```ruby
|
|
2087
|
+
response = LoopsSdk::Workflows.list
|
|
2088
|
+
```
|
|
2089
|
+
|
|
2090
|
+
#### Response
|
|
2091
|
+
|
|
2092
|
+
```json
|
|
2093
|
+
{
|
|
2094
|
+
"pagination": {
|
|
2095
|
+
"totalResults": 1,
|
|
2096
|
+
"returnedResults": 1,
|
|
2097
|
+
"perPage": 20,
|
|
2098
|
+
"totalPages": 1,
|
|
2099
|
+
"nextCursor": null,
|
|
2100
|
+
"nextPage": null
|
|
2101
|
+
},
|
|
2102
|
+
"data": [
|
|
2103
|
+
{
|
|
2104
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2105
|
+
"name": "Onboarding",
|
|
2106
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2107
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2108
|
+
}
|
|
2109
|
+
]
|
|
2110
|
+
}
|
|
2111
|
+
```
|
|
2112
|
+
|
|
2113
|
+
---
|
|
2114
|
+
|
|
2115
|
+
### Workflows.create()
|
|
2116
|
+
|
|
2117
|
+
Create a draft workflow with a blank trigger and exit node.
|
|
2118
|
+
|
|
2119
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow)
|
|
2120
|
+
|
|
2121
|
+
#### Parameters
|
|
2122
|
+
|
|
2123
|
+
| Name | Type | Required | Notes |
|
|
2124
|
+
| ----------------- | ------ | -------- | ---------------------------------------------- |
|
|
2125
|
+
| `name` | string | Yes | |
|
|
2126
|
+
| `description` | string | No | |
|
|
2127
|
+
| `mailing_list_id` | string | No | The mailing list the workflow sends to. |
|
|
2128
|
+
|
|
2129
|
+
#### Example
|
|
2130
|
+
|
|
2131
|
+
```ruby
|
|
2132
|
+
response = LoopsSdk::Workflows.create(name: "Welcome series")
|
|
2133
|
+
```
|
|
2134
|
+
|
|
2135
|
+
#### Response
|
|
2136
|
+
|
|
2137
|
+
```json
|
|
2138
|
+
{
|
|
2139
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2140
|
+
"status": "Draft",
|
|
2141
|
+
"name": "Welcome series",
|
|
2142
|
+
"mailingListId": null,
|
|
2143
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2144
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2145
|
+
"nodes": {
|
|
2146
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2147
|
+
"typeName": "BlankTrigger",
|
|
2148
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2149
|
+
},
|
|
2150
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2151
|
+
"typeName": "ExitAction",
|
|
2152
|
+
"nextNodeIds": []
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
```
|
|
2157
|
+
|
|
2158
|
+
---
|
|
2159
|
+
|
|
2160
|
+
### Workflows.get()
|
|
2161
|
+
|
|
2162
|
+
Get a simplified workflow graph.
|
|
2163
|
+
|
|
2164
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow)
|
|
2165
|
+
|
|
2166
|
+
#### Parameters
|
|
2167
|
+
|
|
2168
|
+
| Name | Type | Required | Notes |
|
|
2169
|
+
| ---- | ------ | -------- | ----- |
|
|
2170
|
+
| `workflow_id` | string | Yes | |
|
|
2171
|
+
|
|
2172
|
+
#### Example
|
|
2173
|
+
|
|
2174
|
+
```ruby
|
|
2175
|
+
response = LoopsSdk::Workflows.get(workflow_id: "cls9t2u4v0210rx20jpuary23")
|
|
2176
|
+
```
|
|
2177
|
+
|
|
2178
|
+
#### Response
|
|
2179
|
+
|
|
2180
|
+
```json
|
|
2181
|
+
{
|
|
2182
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2183
|
+
"status": "Draft",
|
|
2184
|
+
"name": "Onboarding",
|
|
2185
|
+
"mailingListId": null,
|
|
2186
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2187
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2188
|
+
"nodes": {
|
|
2189
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2190
|
+
"typeName": "SignupTrigger",
|
|
2191
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2192
|
+
},
|
|
2193
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2194
|
+
"typeName": "ExitAction",
|
|
2195
|
+
"nextNodeIds": []
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
```
|
|
2200
|
+
|
|
2201
|
+
---
|
|
2202
|
+
|
|
2203
|
+
### Workflows.update()
|
|
2204
|
+
|
|
2205
|
+
Update a workflow's display properties. To change the mailing list, use `Workflows.change_mailing_list()`.
|
|
2206
|
+
|
|
2207
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow)
|
|
2208
|
+
|
|
2209
|
+
#### Parameters
|
|
2210
|
+
|
|
2211
|
+
| Name | Type | Required | Notes |
|
|
2212
|
+
| ------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2213
|
+
| `workflow_id` | string | Yes | |
|
|
2214
|
+
| `expected_revision_id` | string | Yes | The `workflowRevisionId` from the latest read or mutation. Pass `nil` for older workflows. |
|
|
2215
|
+
| `name` | string | No | |
|
|
2216
|
+
| `description` | string | No | |
|
|
2217
|
+
|
|
2218
|
+
At least one of `name` or `description` must be provided.
|
|
2219
|
+
|
|
2220
|
+
#### Example
|
|
2221
|
+
|
|
2222
|
+
```ruby
|
|
2223
|
+
response = LoopsSdk::Workflows.update(
|
|
2224
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2225
|
+
expected_revision_id: "rev_123",
|
|
2226
|
+
name: "Updated name"
|
|
2227
|
+
)
|
|
2228
|
+
```
|
|
2229
|
+
|
|
2230
|
+
#### Response
|
|
2231
|
+
|
|
2232
|
+
```json
|
|
2233
|
+
{
|
|
2234
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2235
|
+
"status": "Draft",
|
|
2236
|
+
"name": "Updated name",
|
|
2237
|
+
"mailingListId": null,
|
|
2238
|
+
"rootNodeId": "cf16k73gq014h3mmj5b6jdi9r",
|
|
2239
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2240
|
+
"nodes": {
|
|
2241
|
+
"cf16k73gq014h3mmj5b6jdi9r": {
|
|
2242
|
+
"typeName": "BlankTrigger",
|
|
2243
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"]
|
|
2244
|
+
},
|
|
2245
|
+
"cf16k73gq014h3mmj5b4jdifg": {
|
|
2246
|
+
"typeName": "ExitAction",
|
|
2247
|
+
"nextNodeIds": []
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
```
|
|
2252
|
+
|
|
2253
|
+
---
|
|
2254
|
+
|
|
2255
|
+
### Workflows.change_mailing_list()
|
|
2256
|
+
|
|
2257
|
+
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.
|
|
2258
|
+
|
|
2259
|
+
[API Reference](https://loops.so/docs/api-reference/change-workflow-mailing-list)
|
|
2260
|
+
|
|
2261
|
+
#### Parameters
|
|
2262
|
+
|
|
2263
|
+
| Name | Type | Required | Notes |
|
|
2264
|
+
| ------------------------ | ------- | -------- | --------------------------------------------------------------------- |
|
|
2265
|
+
| `workflow_id` | string | Yes | |
|
|
2266
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2267
|
+
| `mailing_list_id` | string | Yes | Pass `nil` to clear the mailing list. |
|
|
2268
|
+
| `dry_run` | boolean | No | If `true`, validate without modifying. |
|
|
2269
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
2270
|
+
|
|
2271
|
+
#### Example
|
|
2272
|
+
|
|
2273
|
+
```ruby
|
|
2274
|
+
response = LoopsSdk::Workflows.change_mailing_list(
|
|
2275
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2276
|
+
expected_revision_id: "rev_123",
|
|
2277
|
+
mailing_list_id: "cm06f5v0e45nf0ml5754o9cix",
|
|
2278
|
+
dry_run: true
|
|
2279
|
+
)
|
|
2280
|
+
```
|
|
2281
|
+
|
|
2282
|
+
#### Response
|
|
2283
|
+
|
|
2284
|
+
```json
|
|
2285
|
+
{
|
|
2286
|
+
"status": "updated",
|
|
2287
|
+
"mailingListId": "cm06f5v0e45nf0ml5754o9cix",
|
|
2288
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2289
|
+
"queuedContactCount": 0,
|
|
2290
|
+
"queuedContactLimitReached": false
|
|
2291
|
+
}
|
|
2292
|
+
```
|
|
2293
|
+
|
|
2294
|
+
---
|
|
2295
|
+
|
|
2296
|
+
### Workflows.get_node()
|
|
2297
|
+
|
|
2298
|
+
Get detailed data for a single workflow node.
|
|
2299
|
+
|
|
2300
|
+
[API Reference](https://loops.so/docs/api-reference/get-workflow-node)
|
|
2301
|
+
|
|
2302
|
+
#### Parameters
|
|
2303
|
+
|
|
2304
|
+
| Name | Type | Required | Notes |
|
|
2305
|
+
| ------------ | ------ | -------- | ----- |
|
|
2306
|
+
| `workflow_id`| string | Yes | |
|
|
2307
|
+
| `node_id` | string | Yes | |
|
|
2308
|
+
|
|
2309
|
+
#### Example
|
|
2310
|
+
|
|
2311
|
+
```ruby
|
|
2312
|
+
response = LoopsSdk::Workflows.get_node(workflow_id: "cls9t2u4v0210rx20jpuary23", node_id: "clt0u3v5w0232sy31kqvbzs34")
|
|
2313
|
+
```
|
|
2314
|
+
|
|
2315
|
+
#### Response
|
|
2316
|
+
|
|
2317
|
+
```json
|
|
2318
|
+
{
|
|
2319
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2320
|
+
"workflowId": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2321
|
+
"typeName": "TimerAction",
|
|
2322
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2323
|
+
"amount": 1,
|
|
2324
|
+
"unit": "h",
|
|
2325
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2326
|
+
}
|
|
2327
|
+
```
|
|
2328
|
+
|
|
2329
|
+
---
|
|
2330
|
+
|
|
2331
|
+
### Workflows.create_node()
|
|
2332
|
+
|
|
2333
|
+
Create a new default workflow node. Use `insert_mode: "between"` with `from_node_id`/`to_node_id`, or `insert_mode: "before"` with `before_node_id`.
|
|
2334
|
+
|
|
2335
|
+
[API Reference](https://loops.so/docs/api-reference/create-workflow-node)
|
|
2336
|
+
|
|
2337
|
+
#### Parameters
|
|
2338
|
+
|
|
2339
|
+
| Name | Type | Required | Notes |
|
|
2340
|
+
| ---------------------- | ------ | -------- | ---------------------------------------------------------------------------------------------- |
|
|
2341
|
+
| `workflow_id` | string | Yes | |
|
|
2342
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2343
|
+
| `insert_mode` | string | Yes | `between` or `before`. |
|
|
2344
|
+
| `node_type_name` | string | Yes | One of `AudienceFilter`, `BranchNode`, `ExperimentBranchNode`, `TimerAction`, `SendEmailAction`, `VariantNode`. |
|
|
2345
|
+
| `from_node_id` | string | No | Required when `insert_mode` is `between`. |
|
|
2346
|
+
| `to_node_id` | string | No | Required when `insert_mode` is `between`. |
|
|
2347
|
+
| `before_node_id` | string | No | Required when `insert_mode` is `before`. |
|
|
2348
|
+
|
|
2349
|
+
#### Example
|
|
2350
|
+
|
|
2351
|
+
```ruby
|
|
2352
|
+
response = LoopsSdk::Workflows.create_node(
|
|
2353
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2354
|
+
expected_revision_id: "rev_123",
|
|
2355
|
+
insert_mode: "between",
|
|
2356
|
+
node_type_name: "TimerAction",
|
|
2357
|
+
from_node_id: "node_a",
|
|
2358
|
+
to_node_id: "node_b"
|
|
2359
|
+
)
|
|
2360
|
+
```
|
|
2361
|
+
|
|
2362
|
+
#### Response
|
|
2363
|
+
|
|
2364
|
+
```json
|
|
2365
|
+
{
|
|
2366
|
+
"node": {
|
|
2367
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2368
|
+
"typeName": "TimerAction",
|
|
2369
|
+
"nextNodeIds": ["node_b"],
|
|
2370
|
+
"amount": 0,
|
|
2371
|
+
"unit": "m",
|
|
2372
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2373
|
+
},
|
|
2374
|
+
"workflow": {
|
|
2375
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2376
|
+
"status": "Draft",
|
|
2377
|
+
"name": "Welcome series",
|
|
2378
|
+
"mailingListId": null,
|
|
2379
|
+
"rootNodeId": "node_a",
|
|
2380
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2381
|
+
"nodes": {
|
|
2382
|
+
"node_a": {
|
|
2383
|
+
"typeName": "BlankTrigger",
|
|
2384
|
+
"nextNodeIds": ["cln8p0q2r4s6t8u0v2w4x6z8"]
|
|
2385
|
+
},
|
|
2386
|
+
"cln8p0q2r4s6t8u0v2w4x6z8": {
|
|
2387
|
+
"typeName": "TimerAction",
|
|
2388
|
+
"nextNodeIds": ["node_b"],
|
|
2389
|
+
"amount": 0,
|
|
2390
|
+
"unit": "m"
|
|
2391
|
+
},
|
|
2392
|
+
"node_b": {
|
|
2393
|
+
"typeName": "ExitAction",
|
|
2394
|
+
"nextNodeIds": []
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
```
|
|
2400
|
+
|
|
2401
|
+
---
|
|
2402
|
+
|
|
2403
|
+
### Workflows.update_node()
|
|
2404
|
+
|
|
2405
|
+
Update workflow-node-owned fields for a single node.
|
|
2406
|
+
|
|
2407
|
+
[API Reference](https://loops.so/docs/api-reference/update-workflow-node)
|
|
2408
|
+
|
|
2409
|
+
#### Parameters
|
|
2410
|
+
|
|
2411
|
+
| Name | Type | Required | Notes |
|
|
2412
|
+
| ---------------------- | ------ | -------- | ---------------------------------------------------------- |
|
|
2413
|
+
| `workflow_id` | string | Yes | |
|
|
2414
|
+
| `node_id` | string | Yes | |
|
|
2415
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2416
|
+
| `payload` | object | Yes | Node-type-specific fields. See the API reference. |
|
|
2417
|
+
|
|
2418
|
+
#### Example
|
|
2419
|
+
|
|
2420
|
+
```ruby
|
|
2421
|
+
response = LoopsSdk::Workflows.update_node(
|
|
2422
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2423
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2424
|
+
expected_revision_id: "rev_123",
|
|
2425
|
+
payload: { amount: 2, unit: "d" }
|
|
2426
|
+
)
|
|
2427
|
+
```
|
|
2428
|
+
|
|
2429
|
+
#### Response
|
|
2430
|
+
|
|
2431
|
+
```json
|
|
2432
|
+
{
|
|
2433
|
+
"id": "cln8p0q2r4s6t8u0v2w4x6z8",
|
|
2434
|
+
"workflowId": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2435
|
+
"typeName": "TimerAction",
|
|
2436
|
+
"nextNodeIds": ["cf16k73gq014h3mmj5b4jdifg"],
|
|
2437
|
+
"amount": 2,
|
|
2438
|
+
"unit": "d",
|
|
2439
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2440
|
+
}
|
|
2441
|
+
```
|
|
2442
|
+
|
|
2443
|
+
---
|
|
2444
|
+
|
|
2445
|
+
### Workflows.delete_node()
|
|
2446
|
+
|
|
2447
|
+
Delete a single workflow node. If contacts are queued, the API returns `"status": "queuedContactsFound"` — retry with `queued_contact_policy: "discard"` to delete.
|
|
2448
|
+
|
|
2449
|
+
[API Reference](https://loops.so/docs/api-reference/delete-workflow-node)
|
|
2450
|
+
|
|
2451
|
+
#### Parameters
|
|
2452
|
+
|
|
2453
|
+
| Name | Type | Required | Notes |
|
|
2454
|
+
| ----------------------- | ------- | -------- | ------------------------------ |
|
|
2455
|
+
| `workflow_id` | string | Yes | |
|
|
2456
|
+
| `node_id` | string | Yes | |
|
|
2457
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows.|
|
|
2458
|
+
| `dry_run` | boolean | No | |
|
|
2459
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
2460
|
+
|
|
2461
|
+
#### Example
|
|
2462
|
+
|
|
2463
|
+
```ruby
|
|
2464
|
+
response = LoopsSdk::Workflows.delete_node(
|
|
2465
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2466
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2467
|
+
expected_revision_id: "rev_123",
|
|
2468
|
+
dry_run: true
|
|
2469
|
+
)
|
|
2470
|
+
```
|
|
2471
|
+
|
|
2472
|
+
#### Response
|
|
2473
|
+
|
|
2474
|
+
```json
|
|
2475
|
+
{
|
|
2476
|
+
"status": "deleted",
|
|
2477
|
+
"nodeIds": ["clt0u3v5w0232sy31kqvbzs34"],
|
|
2478
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2479
|
+
"queuedContactCount": 0,
|
|
2480
|
+
"queuedContactLimitReached": false
|
|
2481
|
+
}
|
|
2482
|
+
```
|
|
2483
|
+
|
|
2484
|
+
---
|
|
2485
|
+
|
|
2486
|
+
### Workflows.add_branch()
|
|
2487
|
+
|
|
2488
|
+
Add a branch and child node under an existing `BranchNode` or `ExperimentBranchNode`.
|
|
2489
|
+
|
|
2490
|
+
[API Reference](https://loops.so/docs/api-reference/add-workflow-branch)
|
|
2491
|
+
|
|
2492
|
+
#### Parameters
|
|
2493
|
+
|
|
2494
|
+
| Name | Type | Required | Notes |
|
|
2495
|
+
| ---------------------- | ------ | -------- | ------------------------------- |
|
|
2496
|
+
| `workflow_id` | string | Yes | |
|
|
2497
|
+
| `node_id` | string | Yes | The branch or experiment node. |
|
|
2498
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows. |
|
|
2499
|
+
|
|
2500
|
+
#### Example
|
|
2501
|
+
|
|
2502
|
+
```ruby
|
|
2503
|
+
response = LoopsSdk::Workflows.add_branch(
|
|
2504
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2505
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2506
|
+
expected_revision_id: "rev_123"
|
|
2507
|
+
)
|
|
2508
|
+
```
|
|
2509
|
+
|
|
2510
|
+
#### Response
|
|
2511
|
+
|
|
2512
|
+
```json
|
|
2513
|
+
{
|
|
2514
|
+
"node": {
|
|
2515
|
+
"id": "cln0a2b4c6d8e0f2g4h6i8j0",
|
|
2516
|
+
"typeName": "AudienceFilter",
|
|
2517
|
+
"nextNodeIds": [],
|
|
2518
|
+
"appliesDownstream": false,
|
|
2519
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6"
|
|
2520
|
+
},
|
|
2521
|
+
"workflow": {
|
|
2522
|
+
"id": "clw1a3b5c7d9e1f3g5h7i9j1",
|
|
2523
|
+
"status": "Draft",
|
|
2524
|
+
"name": "Welcome series",
|
|
2525
|
+
"mailingListId": null,
|
|
2526
|
+
"rootNodeId": "clt0u3v5w0232sy31kqvbzs34",
|
|
2527
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2528
|
+
"nodes": {
|
|
2529
|
+
"clt0u3v5w0232sy31kqvbzs34": {
|
|
2530
|
+
"typeName": "BranchNode",
|
|
2531
|
+
"nextNodeIds": ["cln0a2b4c6d8e0f2g4h6i8j0"]
|
|
2532
|
+
},
|
|
2533
|
+
"cln0a2b4c6d8e0f2g4h6i8j0": {
|
|
2534
|
+
"typeName": "AudienceFilter",
|
|
2535
|
+
"nextNodeIds": []
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
```
|
|
2541
|
+
|
|
2542
|
+
---
|
|
2543
|
+
|
|
2544
|
+
### Workflows.delete_node_recursive()
|
|
2545
|
+
|
|
2546
|
+
Delete a node and its downstream subtree.
|
|
2547
|
+
|
|
2548
|
+
[API Reference](https://loops.so/docs/api-reference/delete-workflow-nodes)
|
|
2549
|
+
|
|
2550
|
+
#### Parameters
|
|
2551
|
+
|
|
2552
|
+
| Name | Type | Required | Notes |
|
|
2553
|
+
| ----------------------- | ------- | -------- | ------------------------------ |
|
|
2554
|
+
| `workflow_id` | string | Yes | |
|
|
2555
|
+
| `node_id` | string | Yes | Root of the subtree to delete. |
|
|
2556
|
+
| `expected_revision_id` | string | Yes | Pass `nil` for older workflows.|
|
|
2557
|
+
| `dry_run` | boolean | No | |
|
|
2558
|
+
| `queued_contact_policy` | string | No | `fail` (default) or `discard`. |
|
|
2559
|
+
|
|
2560
|
+
#### Example
|
|
2561
|
+
|
|
2562
|
+
```ruby
|
|
2563
|
+
response = LoopsSdk::Workflows.delete_node_recursive(
|
|
2564
|
+
workflow_id: "cls9t2u4v0210rx20jpuary23",
|
|
2565
|
+
node_id: "clt0u3v5w0232sy31kqvbzs34",
|
|
2566
|
+
expected_revision_id: "rev_123",
|
|
2567
|
+
queued_contact_policy: "discard"
|
|
2568
|
+
)
|
|
2569
|
+
```
|
|
2570
|
+
|
|
2571
|
+
#### Response
|
|
2572
|
+
|
|
2573
|
+
```json
|
|
2574
|
+
{
|
|
2575
|
+
"status": "deleted",
|
|
2576
|
+
"nodeIds": [
|
|
2577
|
+
"clt0u3v5w0232sy31kqvbzs34",
|
|
2578
|
+
"cln9q1r3s5t7u9v1w3x5y7z9"
|
|
2579
|
+
],
|
|
2580
|
+
"workflowRevisionId": "clrev0w0r1k2f3l4o5w6",
|
|
2581
|
+
"queuedContactCount": 0,
|
|
2582
|
+
"queuedContactLimitReached": false
|
|
2583
|
+
}
|
|
2584
|
+
```
|
|
2585
|
+
|
|
2586
|
+
---
|
|
2587
|
+
|
|
2588
|
+
### EventPatterns.list()
|
|
2589
|
+
|
|
2590
|
+
List event patterns available to workflow event trigger nodes.
|
|
2591
|
+
|
|
2592
|
+
[API Reference](https://loops.so/docs/api-reference/list-event-patterns)
|
|
2593
|
+
|
|
2594
|
+
#### Parameters
|
|
2595
|
+
|
|
2596
|
+
| Name | Type | Required | Notes |
|
|
2597
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2598
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2599
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2600
|
+
|
|
2601
|
+
#### Example
|
|
2602
|
+
|
|
2603
|
+
```ruby
|
|
2604
|
+
response = LoopsSdk::EventPatterns.list
|
|
2605
|
+
```
|
|
2606
|
+
|
|
2607
|
+
#### Response
|
|
2608
|
+
|
|
2609
|
+
```json
|
|
2610
|
+
{
|
|
2611
|
+
"pagination": {
|
|
2612
|
+
"totalResults": 1,
|
|
2613
|
+
"returnedResults": 1,
|
|
2614
|
+
"perPage": 20,
|
|
2615
|
+
"totalPages": 1,
|
|
2616
|
+
"nextCursor": null,
|
|
2617
|
+
"nextPage": null
|
|
2618
|
+
},
|
|
2619
|
+
"data": [
|
|
2620
|
+
{
|
|
2621
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
2622
|
+
"eventName": "signup",
|
|
2623
|
+
"incomingWebhookPlatform": null
|
|
2624
|
+
}
|
|
2625
|
+
]
|
|
2626
|
+
}
|
|
2627
|
+
```
|
|
2628
|
+
|
|
2629
|
+
---
|
|
2630
|
+
|
|
2631
|
+
### EventPatterns.get()
|
|
2632
|
+
|
|
2633
|
+
Get an event pattern by ID.
|
|
2634
|
+
|
|
2635
|
+
[API Reference](https://loops.so/docs/api-reference/get-event-pattern)
|
|
2636
|
+
|
|
2637
|
+
#### Parameters
|
|
2638
|
+
|
|
2639
|
+
| Name | Type | Required | Notes |
|
|
2640
|
+
| ------------------ | ------ | -------- | ----- |
|
|
2641
|
+
| `event_pattern_id` | string | Yes | |
|
|
2642
|
+
|
|
2643
|
+
#### Example
|
|
2644
|
+
|
|
2645
|
+
```ruby
|
|
2646
|
+
response = LoopsSdk::EventPatterns.get(event_pattern_id: "cle1v2e3n4t5p6a7t8t9e0r1")
|
|
2647
|
+
```
|
|
2648
|
+
|
|
2649
|
+
#### Response
|
|
2650
|
+
|
|
2651
|
+
```json
|
|
2652
|
+
{
|
|
2653
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
2654
|
+
"eventName": "signup",
|
|
2655
|
+
"eventProperties": [
|
|
2656
|
+
{ "name": "plan", "type": "string" },
|
|
2657
|
+
{ "name": "trialDays", "type": "number" }
|
|
2658
|
+
],
|
|
2659
|
+
"incomingWebhookPlatform": null
|
|
2660
|
+
}
|
|
2661
|
+
```
|
|
2662
|
+
|
|
2663
|
+
---
|
|
2664
|
+
|
|
2665
|
+
### EventPatterns.get_by_name()
|
|
2666
|
+
|
|
2667
|
+
Get an event pattern by event name. Event names are case-sensitive.
|
|
2668
|
+
|
|
2669
|
+
[API Reference](https://loops.so/docs/api-reference/get-event-pattern-by-name)
|
|
2670
|
+
|
|
2671
|
+
#### Parameters
|
|
2672
|
+
|
|
2673
|
+
| Name | Type | Required | Notes |
|
|
2674
|
+
| ------------ | ------ | -------- | ----- |
|
|
2675
|
+
| `event_name` | string | Yes | |
|
|
2676
|
+
|
|
2677
|
+
#### Example
|
|
2678
|
+
|
|
2679
|
+
```ruby
|
|
2680
|
+
response = LoopsSdk::EventPatterns.get_by_name(event_name: "signup")
|
|
2681
|
+
```
|
|
2682
|
+
|
|
2683
|
+
#### Response
|
|
2684
|
+
|
|
2685
|
+
```json
|
|
2686
|
+
{
|
|
2687
|
+
"id": "cle1a2b3c004yl70d5e6f7g8h",
|
|
2688
|
+
"eventName": "signup",
|
|
2689
|
+
"eventProperties": [
|
|
2690
|
+
{ "name": "plan", "type": "string" },
|
|
2691
|
+
{ "name": "trialDays", "type": "number" }
|
|
2692
|
+
],
|
|
2693
|
+
"incomingWebhookPlatform": null
|
|
2694
|
+
}
|
|
2695
|
+
```
|
|
2696
|
+
|
|
2697
|
+
---
|
|
2698
|
+
|
|
2699
|
+
### TransactionalGroups.list()
|
|
2700
|
+
|
|
2701
|
+
List transactional groups.
|
|
2702
|
+
|
|
2703
|
+
[API Reference](https://loops.so/docs/api-reference/list-transactional-groups)
|
|
2704
|
+
|
|
2705
|
+
#### Parameters
|
|
2706
|
+
|
|
2707
|
+
| Name | Type | Required | Notes |
|
|
2708
|
+
| --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
2709
|
+
| `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
|
|
2710
|
+
| `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
|
|
2711
|
+
|
|
2712
|
+
#### Example
|
|
2713
|
+
|
|
2714
|
+
```ruby
|
|
2715
|
+
response = LoopsSdk::TransactionalGroups.list
|
|
2716
|
+
```
|
|
2717
|
+
|
|
2718
|
+
#### Response
|
|
2719
|
+
|
|
2720
|
+
```json
|
|
2721
|
+
{
|
|
2722
|
+
"pagination": {
|
|
2723
|
+
"totalResults": 1,
|
|
2724
|
+
"returnedResults": 1,
|
|
2725
|
+
"perPage": 20,
|
|
2726
|
+
"totalPages": 1,
|
|
2727
|
+
"nextCursor": null,
|
|
2728
|
+
"nextPage": null
|
|
2729
|
+
},
|
|
2730
|
+
"data": [
|
|
2731
|
+
{
|
|
2732
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2733
|
+
"name": "Onboarding",
|
|
2734
|
+
"description": "Top of funnel campaigns",
|
|
2735
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2736
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2737
|
+
}
|
|
2738
|
+
]
|
|
2739
|
+
}
|
|
2740
|
+
```
|
|
2741
|
+
|
|
2742
|
+
---
|
|
2743
|
+
|
|
2744
|
+
### TransactionalGroups.create()
|
|
2745
|
+
|
|
2746
|
+
Create a transactional group.
|
|
2747
|
+
|
|
2748
|
+
[API Reference](https://loops.so/docs/api-reference/create-transactional-group)
|
|
2749
|
+
|
|
2750
|
+
#### Parameters
|
|
2751
|
+
|
|
2752
|
+
| Name | Type | Required | Notes |
|
|
2753
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
2754
|
+
| `name` | string | Yes | Cannot be the reserved name "Unsorted". |
|
|
2755
|
+
| `description` | string | No | An optional description for the group. |
|
|
2756
|
+
|
|
2757
|
+
#### Example
|
|
2758
|
+
|
|
2759
|
+
```ruby
|
|
2760
|
+
response = LoopsSdk::TransactionalGroups.create(name: "Account emails")
|
|
2761
|
+
```
|
|
2762
|
+
|
|
2763
|
+
#### Response
|
|
2764
|
+
|
|
2765
|
+
```json
|
|
2766
|
+
{
|
|
2767
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2768
|
+
"name": "Account emails",
|
|
2769
|
+
"description": "",
|
|
2770
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2771
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2772
|
+
}
|
|
2773
|
+
```
|
|
2774
|
+
|
|
2775
|
+
---
|
|
2776
|
+
|
|
2777
|
+
### TransactionalGroups.get()
|
|
2778
|
+
|
|
2779
|
+
Get a transactional group by ID.
|
|
2780
|
+
|
|
2781
|
+
[API Reference](https://loops.so/docs/api-reference/get-transactional-group)
|
|
2782
|
+
|
|
2783
|
+
#### Parameters
|
|
2784
|
+
|
|
2785
|
+
| Name | Type | Required | Notes |
|
|
2786
|
+
| ---- | ------ | -------- | ----- |
|
|
2787
|
+
| `transactional_group_id` | string | Yes | |
|
|
2788
|
+
|
|
2789
|
+
#### Example
|
|
2790
|
+
|
|
2791
|
+
```ruby
|
|
2792
|
+
response = LoopsSdk::TransactionalGroups.get(transactional_group_id: "clv2w3x4y0288xbb0kqrsuv67")
|
|
2793
|
+
```
|
|
2794
|
+
|
|
2795
|
+
#### Response
|
|
2796
|
+
|
|
2797
|
+
```json
|
|
2798
|
+
{
|
|
2799
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2800
|
+
"name": "Account emails",
|
|
2801
|
+
"description": "",
|
|
2802
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2803
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2804
|
+
}
|
|
2805
|
+
```
|
|
2806
|
+
|
|
2807
|
+
---
|
|
2808
|
+
|
|
2809
|
+
### TransactionalGroups.update()
|
|
2810
|
+
|
|
2811
|
+
Update a transactional group's name or description.
|
|
2812
|
+
|
|
2813
|
+
[API Reference](https://loops.so/docs/api-reference/update-transactional-group)
|
|
2814
|
+
|
|
2815
|
+
#### Parameters
|
|
2816
|
+
|
|
2817
|
+
| Name | Type | Required | Notes |
|
|
2818
|
+
| ------------- | ------ | -------- | --------------------------------------- |
|
|
2819
|
+
| `transactional_group_id` | string | Yes | |
|
|
2820
|
+
| `name` | string | No | Cannot be the reserved name "Unsorted". |
|
|
2821
|
+
| `description` | string | No | |
|
|
2822
|
+
|
|
2823
|
+
At least one field must be provided.
|
|
2824
|
+
|
|
2825
|
+
#### Example
|
|
2826
|
+
|
|
2827
|
+
```ruby
|
|
2828
|
+
response = LoopsSdk::TransactionalGroups.update(
|
|
2829
|
+
transactional_group_id: "clv2w3x4y0288xbb0kqrsuv67",
|
|
2830
|
+
name: "Updated name"
|
|
2831
|
+
)
|
|
2832
|
+
```
|
|
2833
|
+
|
|
2834
|
+
#### Response
|
|
2835
|
+
|
|
2836
|
+
```json
|
|
2837
|
+
{
|
|
2838
|
+
"id": "clg7n5p3q1r9s7t5u3v1w9y7",
|
|
2839
|
+
"name": "Updated name",
|
|
2840
|
+
"description": "",
|
|
2841
|
+
"createdAt": "2025-06-29T07:47:39.370Z",
|
|
2842
|
+
"updatedAt": "2025-06-29T07:47:39.370Z"
|
|
2843
|
+
}
|
|
2844
|
+
```
|
|
2845
|
+
|
|
2846
|
+
---
|
|
2847
|
+
|
|
2848
|
+
### Uploads.upload()
|
|
2849
|
+
|
|
2850
|
+
Upload an image file for use in LMX email content.
|
|
2851
|
+
|
|
2852
|
+
Supported image types: JPEG, PNG, GIF, and WebP (max 4 MB). MIME type is detected from file contents, or pass `content_type:` to override.
|
|
2853
|
+
|
|
2854
|
+
[API Reference](https://loops.so/docs/api-reference/create-upload)
|
|
2855
|
+
|
|
2856
|
+
#### Parameters
|
|
2857
|
+
|
|
2858
|
+
| Name | Type | Required | Notes |
|
|
2859
|
+
| --------------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
|
|
2860
|
+
| `path` | string | Yes | Path to the image file on disk. |
|
|
2861
|
+
| `content_type` | string | No | MIME type override. Supported: `image/jpeg`, `image/png`, `image/gif`, `image/webp`. |
|
|
2862
|
+
|
|
2863
|
+
#### Example
|
|
2864
|
+
|
|
2865
|
+
```ruby
|
|
2866
|
+
response = LoopsSdk::Uploads.upload(path: "./header.png")
|
|
2867
|
+
|
|
2868
|
+
# Use the returned URL in LMX
|
|
2869
|
+
lmx = %(<Image src="#{response['finalUrl']}" alt="Header" />)
|
|
2870
|
+
```
|
|
2871
|
+
|
|
2872
|
+
#### Response
|
|
2873
|
+
|
|
2874
|
+
```json
|
|
2875
|
+
{
|
|
2876
|
+
"emailAssetId": "clu1v4w6x0254tz42lrcwat45",
|
|
2877
|
+
"finalUrl": "https://cdn.loops.so/clu1v4w6x0254tz42lrcwat45.png"
|
|
2878
|
+
}
|
|
2879
|
+
```
|
|
2880
|
+
|
|
1132
2881
|
---
|
|
1133
2882
|
|
|
1134
2883
|
## Testing
|
|
@@ -1139,4 +2888,4 @@ Run tests with `bundle exec rspec`.
|
|
|
1139
2888
|
|
|
1140
2889
|
## Contributing
|
|
1141
2890
|
|
|
1142
|
-
Bug reports and pull requests are welcome. Please read our [Contributing Guidelines](CONTRIBUTING.md).
|
|
2891
|
+
Bug reports and pull requests are welcome. Please read our [Contributing Guidelines](CONTRIBUTING.md).
|