loops_sdk 2.2.0 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5f428ed70457f4a5545ae8db80c8c1184053851702186b93e4181de19826bac
4
- data.tar.gz: 273c41adcdfc013281b38e6e7fbf9d1d5f754e3e0e34979b660284689c26d9a6
3
+ metadata.gz: 5a4fac371d3bbc89f778265ecb287032e0ce08846a688b61887a64f27e30f8f4
4
+ data.tar.gz: 4c0647edf1dcebf7927232332ad5d92d8114c5ce8b291b1cbffc0c4dd145455e
5
5
  SHA512:
6
- metadata.gz: cf08a088e5a500fe82ff04a7e432c4bae832a9414ba693c69f9d13ba381a85dcad63e554b09449f3c2f79c1e150a7309f5071b98c4a5a022820f044e93e8216b
7
- data.tar.gz: fa693592b67828b4c1a351a938f2c16bc058f29830f442cab2d009383b9e07a108df1c1fb836c54066c067d0bce222a26f975994b16d1d3348a91780fc783fd5
6
+ metadata.gz: 592a434bc0dd7d9c19c2b209eacd2463373cbeca1ed6d67e8fb376443084ae1e3c24ef95b2ee85d225e6c4ee544badd16fe34b6b80c262192817c77d501cf8a3
7
+ data.tar.gz: 2e979c1b6ddd315fd3adc6d28fedd69bf19322207ca66bf85eef4ea799d4f94dce01ffb55205fe23dcd7da872e132e976a83f11fcb6d0755744388b990a528a9
data/README.md CHANGED
@@ -114,8 +114,13 @@ 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)
@@ -125,8 +130,23 @@ You can use custom contact properties in API calls. Please make sure to [add cus
125
130
  - [Campaigns.create()](#campaignscreate)
126
131
  - [Campaigns.get()](#campaignsget)
127
132
  - [Campaigns.update()](#campaignsupdate)
133
+ - [CampaignGroups.list()](#campaigngroupslist)
134
+ - [CampaignGroups.create()](#campaigngroupscreate)
135
+ - [CampaignGroups.get()](#campaigngroupsget)
136
+ - [CampaignGroups.update()](#campaigngroupsupdate)
137
+ - [AudienceSegments.list()](#audiencesegmentslist)
138
+ - [AudienceSegments.get()](#audiencesegmentsget)
139
+ - [Workflows.list()](#workflowslist)
140
+ - [Workflows.get()](#workflowsget)
141
+ - [Workflows.get_node()](#workflowsget_node)
128
142
  - [EmailMessages.get()](#emailmessagesget)
129
143
  - [EmailMessages.update()](#emailmessagesupdate)
144
+ - [EmailMessages.preview()](#emailmessagespreview)
145
+ - [TransactionalGroups.list()](#transactionalgroupslist)
146
+ - [TransactionalGroups.create()](#transactionalgroupscreate)
147
+ - [TransactionalGroups.get()](#transactionalgroupsget)
148
+ - [TransactionalGroups.update()](#transactionalgroupsupdate)
149
+ - [Uploads.upload()](#uploadsupload)
130
150
 
131
151
  ---
132
152
 
@@ -206,7 +226,7 @@ This method will return a success or error message:
206
226
  ```json
207
227
  {
208
228
  "success": true,
209
- "id": "id_of_contact"
229
+ "id": "cll6b3i8901a9jx0oyktl2m4u"
210
230
  }
211
231
  ```
212
232
 
@@ -270,7 +290,7 @@ This method will return a success or error message:
270
290
  ```json
271
291
  {
272
292
  "success": true,
273
- "id": "id_of_contact"
293
+ "id": "cll6b3i8901a9jx0oyktl2m4u"
274
294
  }
275
295
  ```
276
296
 
@@ -726,6 +746,180 @@ This method will return a success or error:
726
746
 
727
747
  ---
728
748
 
749
+ ### Transactional.list()
750
+
751
+ List transactional emails, most recently created first.
752
+
753
+ [API Reference](https://loops.so/docs/api-reference/list-transactional-emails)
754
+
755
+ #### Parameters
756
+
757
+ | Name | Type | Required | Notes |
758
+ | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
759
+ | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
760
+ | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
761
+
762
+ #### Example
763
+
764
+ ```ruby
765
+ response = LoopsSdk::Transactional.list
766
+
767
+ response = LoopsSdk::Transactional.list(perPage: 15, cursor: "cursor_value")
768
+ ```
769
+
770
+ #### Response
771
+
772
+ ```json
773
+ {
774
+ "pagination": {
775
+ "totalResults": 23,
776
+ "returnedResults": 20,
777
+ "perPage": 20,
778
+ "totalPages": 2,
779
+ "nextCursor": "clyo0q4wo01p59fsecyxqsh38",
780
+ "nextPage": "https://app.loops.so/api/v1/transactional-emails?cursor=clyo0q4wo01p59fsecyxqsh38&perPage=20"
781
+ },
782
+ "data": [
783
+ {
784
+ "id": "clfn0k1yg001imo0fdeqg30i8",
785
+ "name": "Welcome email",
786
+ "draftEmailMessageId": null,
787
+ "publishedEmailMessageId": "cly8k3m0n0044jpx2bghepq45",
788
+ "createdAt": "2023-11-06T17:48:07.249Z",
789
+ "updatedAt": "2023-11-06T17:48:07.249Z",
790
+ "dataVariables": ["confirmationUrl"]
791
+ }
792
+ ]
793
+ }
794
+ ```
795
+
796
+ ---
797
+
798
+ ### Transactional.create()
799
+
800
+ Create a transactional email. An empty draft email message is created automatically.
801
+
802
+ [API Reference](https://loops.so/docs/api-reference/create-transactional-email)
803
+
804
+ #### Parameters
805
+
806
+ | Name | Type | Required | Notes |
807
+ | ------------------------ | ------ | -------- | ------------------------------------------------------- |
808
+ | `name` | string | Yes | |
809
+ | `transactional_group_id` | string | No | The ID of the group to add this transactional email to. |
810
+
811
+ #### Example
812
+
813
+ ```ruby
814
+ response = LoopsSdk::Transactional.create(name: "Welcome email")
815
+ ```
816
+
817
+ #### Response
818
+
819
+ Returns the transactional email with `draftEmailMessageId` and `draftEmailMessageContentRevisionId`. Use these when updating the draft via `EmailMessages.update()`.
820
+
821
+ ```json
822
+ {
823
+ "id": "clfq6dinn000yl70fgwwyp82l",
824
+ "name": "Welcome email",
825
+ "draftEmailMessageId": "cly8k3m0n0044jpx2bghepq45",
826
+ "draftEmailMessageContentRevisionId": "clm9n4o6p0088lrz4dijslt67",
827
+ "publishedEmailMessageId": null,
828
+ "createdAt": "2023-11-06T17:48:07.249Z",
829
+ "updatedAt": "2023-11-06T17:48:07.249Z",
830
+ "dataVariables": []
831
+ }
832
+ ```
833
+
834
+ ---
835
+
836
+ ### Transactional.get()
837
+
838
+ Get a single transactional email by ID.
839
+
840
+ [API Reference](https://loops.so/docs/api-reference/get-transactional-email)
841
+
842
+ #### Parameters
843
+
844
+ | Name | Type | Required | Notes |
845
+ | ------------------ | ------ | -------- | ----- |
846
+ | `transactional_id` | string | Yes | |
847
+
848
+ #### Example
849
+
850
+ ```ruby
851
+ response = LoopsSdk::Transactional.get(transactional_id: "clfq6dinn000yl70fgwwyp82l")
852
+ ```
853
+
854
+ ---
855
+
856
+ ### Transactional.update()
857
+
858
+ Update a transactional email's name.
859
+
860
+ [API Reference](https://loops.so/docs/api-reference/update-transactional-email)
861
+
862
+ #### Parameters
863
+
864
+ | Name | Type | Required | Notes |
865
+ | ------------------------ | ------ | -------- | ------------------------------------------------------------ |
866
+ | `transactional_id` | string | Yes | |
867
+ | `name` | string | No | |
868
+ | `transactional_group_id` | string | No | The ID of the group to move this transactional email to. |
869
+
870
+ At least one field must be provided.
871
+
872
+ #### Example
873
+
874
+ ```ruby
875
+ response = LoopsSdk::Transactional.update(
876
+ transactional_id: "clfq6dinn000yl70fgwwyp82l",
877
+ name: "Updated name"
878
+ )
879
+ ```
880
+
881
+ ---
882
+
883
+ ### Transactional.ensure_draft()
884
+
885
+ 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.
886
+
887
+ [API Reference](https://loops.so/docs/api-reference/ensure-transactional-email-draft)
888
+
889
+ #### Parameters
890
+
891
+ | Name | Type | Required | Notes |
892
+ | ------------------ | ------ | -------- | ----- |
893
+ | `transactional_id` | string | Yes | |
894
+
895
+ #### Example
896
+
897
+ ```ruby
898
+ response = LoopsSdk::Transactional.ensure_draft(transactional_id: "clfq6dinn000yl70fgwwyp82l")
899
+ ```
900
+
901
+ ---
902
+
903
+ ### Transactional.publish()
904
+
905
+ Publish a transactional email's current draft. The draft becomes the published version and the draft is cleared.
906
+
907
+ [API Reference](https://loops.so/docs/api-reference/publish-transactional-email)
908
+
909
+ #### Parameters
910
+
911
+ | Name | Type | Required | Notes |
912
+ | ------------------ | ------ | -------- | ----- |
913
+ | `transactional_id` | string | Yes | |
914
+
915
+ #### Example
916
+
917
+ ```ruby
918
+ response = LoopsSdk::Transactional.publish(transactional_id: "clfq6dinn000yl70fgwwyp82l")
919
+ ```
920
+
921
+ ---
922
+
729
923
  ### Transactional.send()
730
924
 
731
925
  Send a transactional email to a contact. [Learn about sending transactional email](https://loops.so/docs/transactional/guide)
@@ -736,7 +930,7 @@ Send a transactional email to a contact. [Learn about sending transactional emai
736
930
 
737
931
  | Name | Type | Required | Notes |
738
932
  | ---------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
739
- | `transactional_id` | string | Yes | The ID of the transactional email to send. |
933
+ | `transactional_id` | string | Yes | The ID of the transactional email to send. |
740
934
  | `email` | string | Yes | The email address of the recipient. |
741
935
  | `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
936
  | `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,68 +1013,6 @@ If there is a problem with the request, a descriptive error message will be retu
819
1013
 
820
1014
  ---
821
1015
 
822
- ### Transactional.list()
823
-
824
- Get a list of published transactional emails.
825
-
826
- [API Reference](https://loops.so/docs/api-reference/list-transactional-emails)
827
-
828
- #### Parameters
829
-
830
- | Name | Type | Required | Notes |
831
- | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
832
- | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
833
- | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
834
-
835
- #### Example
836
-
837
- ```ruby
838
- response = LoopsSdk::Transactional.list
839
-
840
- response = LoopsSdk::Transactional.list(perPage: 15)
841
- ```
842
-
843
- #### Response
844
-
845
- ```json
846
- {
847
- "pagination": {
848
- "totalResults": 23,
849
- "returnedResults": 20,
850
- "perPage": 20,
851
- "totalPages": 2,
852
- "nextCursor": "clyo0q4wo01p59fsecyxqsh38",
853
- "nextPage": "https://app.loops.so/api/v1/transactional?cursor=clyo0q4wo01p59fsecyxqsh38&perPage=20"
854
- },
855
- "data": [
856
- {
857
- "id": "clfn0k1yg001imo0fdeqg30i8",
858
- "lastUpdated": "2023-11-06T17:48:07.249Z",
859
- "dataVariables": []
860
- },
861
- {
862
- "id": "cll42l54f20i1la0lfooe3z12",
863
- "lastUpdated": "2025-02-02T02:56:28.845Z",
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
- ...
878
- ]
879
- }
880
- ```
881
-
882
- ---
883
-
884
1016
  ### DedicatedSendingIps.list()
885
1017
 
886
1018
  Get Loops' dedicated sending IP addresses.
@@ -940,12 +1072,12 @@ Get a single theme by ID.
940
1072
 
941
1073
  | Name | Type | Required | Notes |
942
1074
  | ---------- | ------ | -------- | ----- |
943
- | `theme_id` | string | Yes | |
1075
+ | `theme_id` | string | Yes | |
944
1076
 
945
1077
  #### Example
946
1078
 
947
1079
  ```ruby
948
- response = LoopsSdk::Themes.get(theme_id: "theme_123")
1080
+ response = LoopsSdk::Themes.get(theme_id: "clo5p8q0r0132ntx6flkunw89")
949
1081
  ```
950
1082
 
951
1083
  ---
@@ -981,12 +1113,12 @@ Get a single component by ID.
981
1113
 
982
1114
  | Name | Type | Required | Notes |
983
1115
  | -------------- | ------ | -------- | ----- |
984
- | `component_id` | string | Yes | |
1116
+ | `component_id` | string | Yes | |
985
1117
 
986
1118
  #### Example
987
1119
 
988
1120
  ```ruby
989
- response = LoopsSdk::Components.get(component_id: "component_123")
1121
+ response = LoopsSdk::Components.get(component_id: "clp6q9r1s0154ouy7gmlovx90")
990
1122
  ```
991
1123
 
992
1124
  ---
@@ -1020,14 +1152,25 @@ Create a draft campaign. An empty email message is created automatically.
1020
1152
 
1021
1153
  #### Parameters
1022
1154
 
1023
- | Name | Type | Required | Notes |
1024
- | ------ | ------ | -------- | ----- |
1025
- | `name` | string | Yes | |
1155
+ | Name | Type | Required | Notes |
1156
+ | ---------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- |
1157
+ | `name` | string | Yes | |
1158
+ | `campaign_group_id` | string | No | The ID of the group to add this campaign to. |
1159
+ | `mailing_list_id` | string | No | The ID of the mailing list to send to. |
1160
+ | `audience_segment_id` | string | No | The ID of an audience segment. Setting this clears any `audience_filter`. |
1161
+ | `audience_filter` | object | No | A tree of audience conditions. See the API reference for the filter schema. |
1162
+ | `scheduling` | object | No | When the campaign should send. Use `{ method: "now" }` or `{ method: "schedule", timestamp: "..." }`. |
1026
1163
 
1027
1164
  #### Example
1028
1165
 
1029
1166
  ```ruby
1030
1167
  response = LoopsSdk::Campaigns.create(name: "Spring announcement")
1168
+
1169
+ response = LoopsSdk::Campaigns.create(
1170
+ name: "Spring announcement",
1171
+ mailing_list_id: "cm06f5v0e45nf0ml5754o9cix",
1172
+ scheduling: { method: "schedule", timestamp: "2026-06-01T10:00:00Z" }
1173
+ )
1031
1174
  ```
1032
1175
 
1033
1176
  ---
@@ -1042,34 +1185,41 @@ Get a single campaign by ID.
1042
1185
 
1043
1186
  | Name | Type | Required | Notes |
1044
1187
  | ------------- | ------ | -------- | ----- |
1045
- | `campaign_id` | string | Yes | |
1188
+ | `campaign_id` | string | Yes | |
1046
1189
 
1047
1190
  #### Example
1048
1191
 
1049
1192
  ```ruby
1050
- response = LoopsSdk::Campaigns.get(campaign_id: "campaign_123")
1193
+ response = LoopsSdk::Campaigns.get(campaign_id: "cln4o7p9q0110msw5ekjtmv78")
1051
1194
  ```
1052
1195
 
1053
1196
  ---
1054
1197
 
1055
1198
  ### Campaigns.update()
1056
1199
 
1057
- Update a draft campaign's name.
1200
+ Update a draft campaign's name, group, audience, or scheduling.
1058
1201
 
1059
1202
  [API Reference](https://loops.so/docs/api-reference/update-campaign)
1060
1203
 
1061
1204
  #### Parameters
1062
1205
 
1063
- | Name | Type | Required | Notes |
1064
- | ------------- | ------ | -------- | ----- |
1065
- | `campaign_id` | string | Yes | |
1066
- | `name` | string | Yes | |
1206
+ | Name | Type | Required | Notes |
1207
+ | --------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------- |
1208
+ | `campaign_id` | string | Yes | |
1209
+ | `name` | string | No | |
1210
+ | `campaign_group_id` | string | No | The ID of the group to move this campaign to. |
1211
+ | `mailing_list_id` | string | No | The ID of the mailing list to send to. |
1212
+ | `audience_segment_id` | string | No | The ID of an audience segment. Setting this clears any `audience_filter`. |
1213
+ | `audience_filter` | object | No | A tree of audience conditions. See the API reference for the filter schema. |
1214
+ | `scheduling` | object | No | When the campaign should send. Use `{ method: "now" }` or `{ method: "schedule", timestamp: "..." }`. |
1215
+
1216
+ At least one field must be provided.
1067
1217
 
1068
1218
  #### Example
1069
1219
 
1070
1220
  ```ruby
1071
1221
  response = LoopsSdk::Campaigns.update(
1072
- campaign_id: "campaign_123",
1222
+ campaign_id: "cln4o7p9q0110msw5ekjtmv78",
1073
1223
  name: "Updated campaign name"
1074
1224
  )
1075
1225
  ```
@@ -1086,12 +1236,12 @@ Get an email message, including its LMX content.
1086
1236
 
1087
1237
  | Name | Type | Required | Notes |
1088
1238
  | ------------------- | ------ | -------- | ----- |
1089
- | `email_message_id` | string | Yes | |
1239
+ | `email_message_id` | string | Yes | |
1090
1240
 
1091
1241
  #### Example
1092
1242
 
1093
1243
  ```ruby
1094
- response = LoopsSdk::EmailMessages.get(email_message_id: "message_123")
1244
+ response = LoopsSdk::EmailMessages.get(email_message_id: "cly8k3m0n0044jpx2bghepq45")
1095
1245
  ```
1096
1246
 
1097
1247
  ---
@@ -1104,23 +1254,30 @@ Update an email message for a draft campaign.
1104
1254
 
1105
1255
  #### Parameters
1106
1256
 
1107
- | Name | Type | Required | Notes |
1108
- | ------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
1109
- | `email_message_id` | string | Yes | |
1110
- | `expected_revision_id` | string | No | The `contentRevisionId` from your last fetch. Required to avoid stale concurrent updates. |
1111
- | `subject` | string | No | |
1112
- | `preview_text` | string | No | |
1113
- | `from_name` | string | No | |
1114
- | `from_email` | string | No | Sender username without `@` or domain. The team's sending domain is appended automatically. |
1115
- | `reply_to_email` | string | No | Must be empty or a valid email address. |
1116
- | `lmx` | string | No | Email body serialized as LMX. Styles must be embedded in the LMX `<Style />` tag. |
1257
+ | Name | Type | Required | Notes |
1258
+ | ------------------------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
1259
+ | `email_message_id` | string | Yes | |
1260
+ | `expected_revision_id` | string | No | The `contentRevisionId` from your last fetch. Required to avoid stale concurrent updates. |
1261
+ | `subject` | string | No | |
1262
+ | `preview_text` | string | No | |
1263
+ | `from_name` | string | No | |
1264
+ | `from_email` | string | No | Sender username without `@` or domain. The team's sending domain is appended automatically. |
1265
+ | `reply_to_email` | string | No | Must be empty or a valid email address. |
1266
+ | `cc_email` | string | No | CC email address. Requires the team to have CC/BCC enabled. |
1267
+ | `bcc_email` | string | No | BCC email address. Requires the team to have CC/BCC enabled. |
1268
+ | `language_code` | string | No | Language code for the email. Requires translation to be enabled for the team. |
1269
+ | `email_format` | string | No | The rendering format of the email. One of `styled` or `plain`. |
1270
+ | `lmx` | string | No | Email body serialized as LMX. Styles must be embedded in the LMX `<Style />` tag. |
1271
+ | `contact_properties_fallbacks` | object | No | Fallback values for contact properties. A null value deletes the fallback. |
1272
+ | `event_properties_fallbacks` | object | No | Fallback values for event properties. A null value deletes the fallback. |
1273
+ | `data_variables_fallbacks` | object | No | Fallback values for data variables. A null value deletes the fallback. |
1117
1274
 
1118
1275
  #### Example
1119
1276
 
1120
1277
  ```ruby
1121
1278
  response = LoopsSdk::EmailMessages.update(
1122
- email_message_id: "message_123",
1123
- expected_revision_id: "revision_123",
1279
+ email_message_id: "cly8k3m0n0044jpx2bghepq45",
1280
+ expected_revision_id: "clm9n4o6p0088lrz4dijslt67",
1124
1281
  subject: "Spring announcement",
1125
1282
  preview_text: "See what's new",
1126
1283
  from_name: "Loops",
@@ -1131,6 +1288,350 @@ response = LoopsSdk::EmailMessages.update(
1131
1288
 
1132
1289
  ---
1133
1290
 
1291
+ ### EmailMessages.preview()
1292
+
1293
+ Send a test preview of an email message to one or more addresses.
1294
+
1295
+ [API Reference](https://loops.so/docs/api-reference/preview-email-message)
1296
+
1297
+ #### Parameters
1298
+
1299
+ | Name | Type | Required | Notes |
1300
+ | -------------------- | -------- | -------- | --------------------------------------------------------------------------------- |
1301
+ | `email_message_id` | string | Yes | |
1302
+ | `emails` | string[] | Yes | One or more addresses to send the preview to. |
1303
+ | `contact_properties` | object | No | Contact property values to render. Accepted for campaign and workflow previews. |
1304
+ | `event_properties` | object | No | Event property values to render. Accepted for workflow previews only. |
1305
+ | `data_variables` | object | No | Transactional data variables to render. Accepted for transactional previews only. |
1306
+
1307
+ #### Example
1308
+
1309
+ ```ruby
1310
+ response = LoopsSdk::EmailMessages.preview(
1311
+ email_message_id: "cly8k3m0n0044jpx2bghepq45",
1312
+ emails: ["test@example.com"],
1313
+ contact_properties: { firstName: "Alex" }
1314
+ )
1315
+ ```
1316
+
1317
+ ---
1318
+
1319
+ ### CampaignGroups.list()
1320
+
1321
+ List campaign groups.
1322
+
1323
+ [API Reference](https://loops.so/docs/api-reference/list-campaign-groups)
1324
+
1325
+ #### Parameters
1326
+
1327
+ | Name | Type | Required | Notes |
1328
+ | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
1329
+ | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
1330
+ | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
1331
+
1332
+ #### Example
1333
+
1334
+ ```ruby
1335
+ response = LoopsSdk::CampaignGroups.list
1336
+ ```
1337
+
1338
+ ---
1339
+
1340
+ ### CampaignGroups.create()
1341
+
1342
+ Create a campaign group.
1343
+
1344
+ [API Reference](https://loops.so/docs/api-reference/create-campaign-group)
1345
+
1346
+ #### Parameters
1347
+
1348
+ | Name | Type | Required | Notes |
1349
+ | ------------- | ------ | -------- | --------------------------------------- |
1350
+ | `name` | string | Yes | Cannot be the reserved name "Unsorted". |
1351
+ | `description` | string | No | An optional description for the group. |
1352
+
1353
+ #### Example
1354
+
1355
+ ```ruby
1356
+ response = LoopsSdk::CampaignGroups.create(name: "Newsletters", description: "Monthly updates")
1357
+ ```
1358
+
1359
+ ---
1360
+
1361
+ ### CampaignGroups.get()
1362
+
1363
+ Get a campaign group by ID.
1364
+
1365
+ [API Reference](https://loops.so/docs/api-reference/get-campaign-group)
1366
+
1367
+ #### Parameters
1368
+
1369
+ | Name | Type | Required | Notes |
1370
+ | ---- | ------ | -------- | ----- |
1371
+ | `campaign_group_id` | string | Yes | |
1372
+
1373
+ #### Example
1374
+
1375
+ ```ruby
1376
+ response = LoopsSdk::CampaignGroups.get(campaign_group_id: "clq7r0s2t0176pvz8hnmpwy01")
1377
+ ```
1378
+
1379
+ ---
1380
+
1381
+ ### CampaignGroups.update()
1382
+
1383
+ Update a campaign group's name or description.
1384
+
1385
+ [API Reference](https://loops.so/docs/api-reference/update-campaign-group)
1386
+
1387
+ #### Parameters
1388
+
1389
+ | Name | Type | Required | Notes |
1390
+ | ------------- | ------ | -------- | --------------------------------------- |
1391
+ | `campaign_group_id` | string | Yes | |
1392
+ | `name` | string | No | Cannot be the reserved name "Unsorted". |
1393
+ | `description` | string | No | |
1394
+
1395
+ At least one field must be provided.
1396
+
1397
+ #### Example
1398
+
1399
+ ```ruby
1400
+ response = LoopsSdk::CampaignGroups.update(
1401
+ campaign_group_id: "clq7r0s2t0176pvz8hnmpwy01",
1402
+ name: "Updated name"
1403
+ )
1404
+ ```
1405
+
1406
+ ---
1407
+
1408
+ ### AudienceSegments.list()
1409
+
1410
+ List audience segments.
1411
+
1412
+ [API Reference](https://loops.so/docs/api-reference/list-audience-segments)
1413
+
1414
+ #### Parameters
1415
+
1416
+ | Name | Type | Required | Notes |
1417
+ | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
1418
+ | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
1419
+ | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
1420
+
1421
+ #### Example
1422
+
1423
+ ```ruby
1424
+ response = LoopsSdk::AudienceSegments.list
1425
+ ```
1426
+
1427
+ ---
1428
+
1429
+ ### AudienceSegments.get()
1430
+
1431
+ Get an audience segment by ID.
1432
+
1433
+ [API Reference](https://loops.so/docs/api-reference/get-audience-segment)
1434
+
1435
+ #### Parameters
1436
+
1437
+ | Name | Type | Required | Notes |
1438
+ | ---- | ------ | -------- | ----- |
1439
+ | `audience_segment_id` | string | Yes | |
1440
+
1441
+ #### Example
1442
+
1443
+ ```ruby
1444
+ response = LoopsSdk::AudienceSegments.get(audience_segment_id: "clr8s1t3u0198qw09iotqzx12")
1445
+ ```
1446
+
1447
+ ---
1448
+
1449
+ ### Workflows.list()
1450
+
1451
+ List workflows.
1452
+
1453
+ [API Reference](https://loops.so/docs/api-reference/list-workflows)
1454
+
1455
+ #### Parameters
1456
+
1457
+ | Name | Type | Required | Notes |
1458
+ | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
1459
+ | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
1460
+ | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
1461
+
1462
+ #### Example
1463
+
1464
+ ```ruby
1465
+ response = LoopsSdk::Workflows.list
1466
+ ```
1467
+
1468
+ ---
1469
+
1470
+ ### Workflows.get()
1471
+
1472
+ Get a simplified workflow graph.
1473
+
1474
+ [API Reference](https://loops.so/docs/api-reference/get-workflow)
1475
+
1476
+ #### Parameters
1477
+
1478
+ | Name | Type | Required | Notes |
1479
+ | ---- | ------ | -------- | ----- |
1480
+ | `workflow_id` | string | Yes | |
1481
+
1482
+ #### Example
1483
+
1484
+ ```ruby
1485
+ response = LoopsSdk::Workflows.get(workflow_id: "cls9t2u4v0210rx20jpuary23")
1486
+ ```
1487
+
1488
+ ---
1489
+
1490
+ ### Workflows.get_node()
1491
+
1492
+ Get detailed data for a single workflow node.
1493
+
1494
+ [API Reference](https://loops.so/docs/api-reference/get-workflow-node)
1495
+
1496
+ #### Parameters
1497
+
1498
+ | Name | Type | Required | Notes |
1499
+ | ------------ | ------ | -------- | ----- |
1500
+ | `workflow_id`| string | Yes | |
1501
+ | `node_id` | string | Yes | |
1502
+
1503
+ #### Example
1504
+
1505
+ ```ruby
1506
+ response = LoopsSdk::Workflows.get_node(workflow_id: "cls9t2u4v0210rx20jpuary23", node_id: "clt0u3v5w0232sy31kqvbzs34")
1507
+ ```
1508
+
1509
+ ---
1510
+
1511
+ ### TransactionalGroups.list()
1512
+
1513
+ List transactional groups.
1514
+
1515
+ [API Reference](https://loops.so/docs/api-reference/list-transactional-groups)
1516
+
1517
+ #### Parameters
1518
+
1519
+ | Name | Type | Required | Notes |
1520
+ | --------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
1521
+ | `perPage` | integer | No | How many results to return per page. Must be between 10 and 50. Defaults to 20 if omitted. |
1522
+ | `cursor` | string | No | A cursor, to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. |
1523
+
1524
+ #### Example
1525
+
1526
+ ```ruby
1527
+ response = LoopsSdk::TransactionalGroups.list
1528
+ ```
1529
+
1530
+ ---
1531
+
1532
+ ### TransactionalGroups.create()
1533
+
1534
+ Create a transactional group.
1535
+
1536
+ [API Reference](https://loops.so/docs/api-reference/create-transactional-group)
1537
+
1538
+ #### Parameters
1539
+
1540
+ | Name | Type | Required | Notes |
1541
+ | ------------- | ------ | -------- | --------------------------------------- |
1542
+ | `name` | string | Yes | Cannot be the reserved name "Unsorted". |
1543
+ | `description` | string | No | An optional description for the group. |
1544
+
1545
+ #### Example
1546
+
1547
+ ```ruby
1548
+ response = LoopsSdk::TransactionalGroups.create(name: "Account emails")
1549
+ ```
1550
+
1551
+ ---
1552
+
1553
+ ### TransactionalGroups.get()
1554
+
1555
+ Get a transactional group by ID.
1556
+
1557
+ [API Reference](https://loops.so/docs/api-reference/get-transactional-group)
1558
+
1559
+ #### Parameters
1560
+
1561
+ | Name | Type | Required | Notes |
1562
+ | ---- | ------ | -------- | ----- |
1563
+ | `transactional_group_id` | string | Yes | |
1564
+
1565
+ #### Example
1566
+
1567
+ ```ruby
1568
+ response = LoopsSdk::TransactionalGroups.get(transactional_group_id: "clv2w3x4y0288xbb0kqrsuv67")
1569
+ ```
1570
+
1571
+ ---
1572
+
1573
+ ### TransactionalGroups.update()
1574
+
1575
+ Update a transactional group's name or description.
1576
+
1577
+ [API Reference](https://loops.so/docs/api-reference/update-transactional-group)
1578
+
1579
+ #### Parameters
1580
+
1581
+ | Name | Type | Required | Notes |
1582
+ | ------------- | ------ | -------- | --------------------------------------- |
1583
+ | `transactional_group_id` | string | Yes | |
1584
+ | `name` | string | No | Cannot be the reserved name "Unsorted". |
1585
+ | `description` | string | No | |
1586
+
1587
+ At least one field must be provided.
1588
+
1589
+ #### Example
1590
+
1591
+ ```ruby
1592
+ response = LoopsSdk::TransactionalGroups.update(
1593
+ transactional_group_id: "clv2w3x4y0288xbb0kqrsuv67",
1594
+ name: "Updated name"
1595
+ )
1596
+ ```
1597
+
1598
+ ---
1599
+
1600
+ ### Uploads.upload()
1601
+
1602
+ Upload an image file for use in LMX email content.
1603
+
1604
+ Supported image types: JPEG, PNG, GIF, and WebP (max 4 MB). MIME type is detected from file contents, or pass `content_type:` to override.
1605
+
1606
+ [API Reference](https://loops.so/docs/api-reference/create-upload)
1607
+
1608
+ #### Parameters
1609
+
1610
+ | Name | Type | Required | Notes |
1611
+ | --------------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
1612
+ | `path` | string | Yes | Path to the image file on disk. |
1613
+ | `content_type` | string | No | MIME type override. Supported: `image/jpeg`, `image/png`, `image/gif`, `image/webp`. |
1614
+
1615
+ #### Example
1616
+
1617
+ ```ruby
1618
+ response = LoopsSdk::Uploads.upload(path: "./header.png")
1619
+
1620
+ # Use the returned URL in LMX
1621
+ lmx = %(<Image src="#{response['finalUrl']}" alt="Header" />)
1622
+ ```
1623
+
1624
+ #### Response
1625
+
1626
+ ```json
1627
+ {
1628
+ "emailAssetId": "clu1v4w6x0254tz42lrcwat45",
1629
+ "finalUrl": "https://cdn.loops.so/clu1v4w6x0254tz42lrcwat45.png"
1630
+ }
1631
+ ```
1632
+
1633
+ ---
1634
+
1134
1635
  ## Testing
1135
1636
 
1136
1637
  Run tests with `bundle exec rspec`.
@@ -1139,4 +1640,4 @@ Run tests with `bundle exec rspec`.
1139
1640
 
1140
1641
  ## Contributing
1141
1642
 
1142
- Bug reports and pull requests are welcome. Please read our [Contributing Guidelines](CONTRIBUTING.md).
1643
+ Bug reports and pull requests are welcome. Please read our [Contributing Guidelines](CONTRIBUTING.md).
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class AudienceSegments < Base
5
+ class << self
6
+ def list(perPage: 20, cursor: nil)
7
+ make_request(method: :get, path: "v1/audience-segments", params: { perPage: perPage, cursor: cursor })
8
+ end
9
+
10
+ def get(audience_segment_id:)
11
+ make_request(method: :get, path: "v1/audience-segments/#{audience_segment_id}")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class CampaignGroups < Base
5
+ class << self
6
+ def list(perPage: 20, cursor: nil)
7
+ make_request(method: :get, path: "v1/campaign-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/campaign-groups", body: body)
13
+ end
14
+
15
+ def get(campaign_group_id:)
16
+ make_request(method: :get, path: "v1/campaign-groups/#{campaign_group_id}")
17
+ end
18
+
19
+ def update(campaign_group_id:, name: nil, description: nil)
20
+ body = { name: name, description: description }.compact
21
+ make_request(method: :post, path: "v1/campaign-groups/#{campaign_group_id}", body: body)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -7,16 +7,32 @@ module LoopsSdk
7
7
  make_request(method: :get, path: "v1/campaigns", params: { perPage: perPage, cursor: cursor })
8
8
  end
9
9
 
10
- def create(name:)
11
- make_request(method: :post, path: "v1/campaigns", body: { name: name })
10
+ def create(name:, campaign_group_id: nil, mailing_list_id: nil, audience_segment_id: nil, audience_filter: nil, scheduling: nil)
11
+ body = {
12
+ name: name,
13
+ campaignGroupId: campaign_group_id,
14
+ mailingListId: mailing_list_id,
15
+ audienceSegmentId: audience_segment_id,
16
+ audienceFilter: audience_filter,
17
+ scheduling: scheduling
18
+ }.compact
19
+ make_request(method: :post, path: "v1/campaigns", body: body)
12
20
  end
13
21
 
14
22
  def get(campaign_id:)
15
23
  make_request(method: :get, path: "v1/campaigns/#{campaign_id}")
16
24
  end
17
25
 
18
- def update(campaign_id:, name:)
19
- make_request(method: :post, path: "v1/campaigns/#{campaign_id}", body: { name: name })
26
+ def update(campaign_id:, name: nil, campaign_group_id: nil, mailing_list_id: nil, audience_segment_id: nil, audience_filter: nil, scheduling: nil)
27
+ body = {
28
+ name: name,
29
+ campaignGroupId: campaign_group_id,
30
+ mailingListId: mailing_list_id,
31
+ audienceSegmentId: audience_segment_id,
32
+ audienceFilter: audience_filter,
33
+ scheduling: scheduling
34
+ }.compact
35
+ make_request(method: :post, path: "v1/campaigns/#{campaign_id}", body: body)
20
36
  end
21
37
  end
22
38
  end
@@ -7,7 +7,23 @@ module LoopsSdk
7
7
  make_request(method: :get, path: "v1/email-messages/#{email_message_id}")
8
8
  end
9
9
 
10
- def update(email_message_id:, expected_revision_id: nil, subject: nil, preview_text: nil, from_name: nil, from_email: nil, reply_to_email: nil, lmx: nil)
10
+ def update(
11
+ email_message_id:,
12
+ expected_revision_id: nil,
13
+ subject: nil,
14
+ preview_text: nil,
15
+ from_name: nil,
16
+ from_email: nil,
17
+ reply_to_email: nil,
18
+ cc_email: nil,
19
+ bcc_email: nil,
20
+ language_code: nil,
21
+ email_format: nil,
22
+ lmx: nil,
23
+ contact_properties_fallbacks: nil,
24
+ event_properties_fallbacks: nil,
25
+ data_variables_fallbacks: nil
26
+ )
11
27
  body = {
12
28
  expectedRevisionId: expected_revision_id,
13
29
  subject: subject,
@@ -15,10 +31,27 @@ module LoopsSdk
15
31
  fromName: from_name,
16
32
  fromEmail: from_email,
17
33
  replyToEmail: reply_to_email,
18
- lmx: lmx
34
+ ccEmail: cc_email,
35
+ bccEmail: bcc_email,
36
+ languageCode: language_code,
37
+ emailFormat: email_format,
38
+ lmx: lmx,
39
+ contactPropertiesFallbacks: contact_properties_fallbacks,
40
+ eventPropertiesFallbacks: event_properties_fallbacks,
41
+ dataVariablesFallbacks: data_variables_fallbacks
19
42
  }.compact
20
43
  make_request(method: :post, path: "v1/email-messages/#{email_message_id}", body: body)
21
44
  end
45
+
46
+ def preview(email_message_id:, emails:, contact_properties: nil, event_properties: nil, data_variables: nil)
47
+ body = {
48
+ emails: emails,
49
+ contactProperties: contact_properties,
50
+ eventProperties: event_properties,
51
+ dataVariables: data_variables
52
+ }.compact
53
+ make_request(method: :post, path: "v1/email-messages/#{email_message_id}/preview", body: body)
54
+ end
22
55
  end
23
56
  end
24
57
  end
@@ -4,8 +4,31 @@ module LoopsSdk
4
4
  class Transactional < Base
5
5
  class << self
6
6
  def list(perPage: 20, cursor: nil)
7
- make_request(method: :get, path: "v1/transactional", params: { perPage: perPage, cursor: cursor })
7
+ make_request(method: :get, path: "v1/transactional-emails", params: { perPage: perPage, cursor: cursor })
8
8
  end
9
+
10
+ def create(name:, transactional_group_id: nil)
11
+ body = { name: name, transactionalGroupId: transactional_group_id }.compact
12
+ make_request(method: :post, path: "v1/transactional-emails", body: body)
13
+ end
14
+
15
+ def get(transactional_id:)
16
+ make_request(method: :get, path: "v1/transactional-emails/#{transactional_id}")
17
+ end
18
+
19
+ def update(transactional_id:, name: nil, transactional_group_id: nil)
20
+ body = { name: name, transactionalGroupId: transactional_group_id }.compact
21
+ make_request(method: :post, path: "v1/transactional-emails/#{transactional_id}", body: body)
22
+ end
23
+
24
+ def ensure_draft(transactional_id:)
25
+ make_request(method: :post, path: "v1/transactional-emails/#{transactional_id}/draft")
26
+ end
27
+
28
+ def publish(transactional_id:)
29
+ make_request(method: :post, path: "v1/transactional-emails/#{transactional_id}/publish")
30
+ end
31
+
9
32
  def send(transactional_id:, email:, add_to_audience: false, data_variables: {}, attachments: [], headers: {})
10
33
  attachments = attachments.map do |attachment|
11
34
  attachment.transform_keys { |key| key == :content_type ? :contentType : key }
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class TransactionalGroups < Base
5
+ class << self
6
+ def list(perPage: 20, cursor: nil)
7
+ make_request(method: :get, path: "v1/transactional-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/transactional-groups", body: body)
13
+ end
14
+
15
+ def get(transactional_group_id:)
16
+ make_request(method: :get, path: "v1/transactional-groups/#{transactional_group_id}")
17
+ end
18
+
19
+ def update(transactional_group_id:, name: nil, description: nil)
20
+ body = { name: name, description: description }.compact
21
+ make_request(method: :post, path: "v1/transactional-groups/#{transactional_group_id}", body: body)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Uploads < Base
5
+ SUPPORTED_CONTENT_TYPES = %w[image/jpeg image/png image/gif image/webp].freeze
6
+
7
+ class << self
8
+ def upload(path:, content_type: nil)
9
+ data = File.binread(path)
10
+ content_type ||= detect_content_type(data)
11
+ validate_content_type!(content_type)
12
+
13
+ create_response = make_request(
14
+ method: :post,
15
+ path: "v1/uploads",
16
+ body: { contentType: content_type, contentLength: data.bytesize }
17
+ )
18
+
19
+ put_to_presigned_url(create_response["presignedUrl"], data, content_type)
20
+
21
+ make_request(
22
+ method: :post,
23
+ path: "v1/uploads/#{create_response["emailAssetId"]}/complete"
24
+ )
25
+ end
26
+
27
+ private
28
+
29
+ def detect_content_type(data)
30
+ if data.start_with?("\xFF\xD8\xFF".b)
31
+ "image/jpeg"
32
+ elsif data.start_with?("\x89PNG\r\n\x1a\n".b)
33
+ "image/png"
34
+ elsif data.start_with?("GIF87a".b, "GIF89a".b)
35
+ "image/gif"
36
+ elsif data.bytesize >= 12 && data[0, 4] == "RIFF".b && data[8, 4] == "WEBP".b
37
+ "image/webp"
38
+ else
39
+ raise ArgumentError,
40
+ "Unable to detect image type. Pass content_type: explicitly. " \
41
+ "Supported types: #{SUPPORTED_CONTENT_TYPES.join(', ')}."
42
+ end
43
+ end
44
+
45
+ def validate_content_type!(content_type)
46
+ return if SUPPORTED_CONTENT_TYPES.include?(content_type)
47
+
48
+ raise ArgumentError,
49
+ "Unsupported content_type: #{content_type}. " \
50
+ "Supported types: #{SUPPORTED_CONTENT_TYPES.join(', ')}."
51
+ end
52
+
53
+ def put_to_presigned_url(url, data, content_type)
54
+ response = Faraday.put(url) do |req|
55
+ req.headers["Content-Type"] = content_type
56
+ req.headers["Content-Length"] = data.bytesize.to_s
57
+ req.body = data
58
+ end
59
+
60
+ return if response.success?
61
+
62
+ raise APIError.new(response.status, response.body)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LoopsSdk
4
- VERSION = "2.2.0"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class Workflows < Base
5
+ class << self
6
+ def list(perPage: 20, cursor: nil)
7
+ make_request(method: :get, path: "v1/workflows", params: { perPage: perPage, cursor: cursor })
8
+ end
9
+
10
+ def get(workflow_id:)
11
+ make_request(method: :get, path: "v1/workflows/#{workflow_id}")
12
+ end
13
+
14
+ def get_node(workflow_id:, node_id:)
15
+ make_request(method: :get, path: "v1/workflows/#{workflow_id}/nodes/#{node_id}")
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/loops_sdk.rb CHANGED
@@ -15,7 +15,12 @@ require_relative "loops_sdk/dedicated_sending_ips"
15
15
  require_relative "loops_sdk/themes"
16
16
  require_relative "loops_sdk/components"
17
17
  require_relative "loops_sdk/campaigns"
18
+ require_relative "loops_sdk/campaign_groups"
18
19
  require_relative "loops_sdk/email_messages"
20
+ require_relative "loops_sdk/uploads"
21
+ require_relative "loops_sdk/audience_segments"
22
+ require_relative "loops_sdk/workflows"
23
+ require_relative "loops_sdk/transactional_groups"
19
24
 
20
25
  module LoopsSdk
21
26
  class << self
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.2.0
4
+ version: 2.3.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-05-21 00:00:00.000000000 Z
11
+ date: 2026-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -35,7 +35,9 @@ files:
35
35
  - README.md
36
36
  - lib/loops_sdk.rb
37
37
  - lib/loops_sdk/api_key.rb
38
+ - lib/loops_sdk/audience_segments.rb
38
39
  - lib/loops_sdk/base.rb
40
+ - lib/loops_sdk/campaign_groups.rb
39
41
  - lib/loops_sdk/campaigns.rb
40
42
  - lib/loops_sdk/components.rb
41
43
  - lib/loops_sdk/configuration.rb
@@ -47,7 +49,10 @@ files:
47
49
  - lib/loops_sdk/mailing_lists.rb
48
50
  - lib/loops_sdk/themes.rb
49
51
  - lib/loops_sdk/transactional.rb
52
+ - lib/loops_sdk/transactional_groups.rb
53
+ - lib/loops_sdk/uploads.rb
50
54
  - lib/loops_sdk/version.rb
55
+ - lib/loops_sdk/workflows.rb
51
56
  homepage: https://loops.so/docs/api-reference
52
57
  licenses:
53
58
  - MIT