loops_sdk 0.1.0 → 0.1.2

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: 2f72e2f62c89ee3d1ba4bf2803ce036d1bbaf0c5090cb59bc5dfed76310e0d64
4
- data.tar.gz: 611b4184d555033ba4c4166426519a4bf9cea4fb47675b4b2b99ed0cafea9a58
3
+ metadata.gz: 85549597f27cc413d5ebafb39a9974172a8f2dfc613e6190c8c1a664f964006b
4
+ data.tar.gz: cd13f142b86862541207dfb9c1ef2531b3712474de3f9320c2649f2fea697fa9
5
5
  SHA512:
6
- metadata.gz: 128ae813b6a85b3420a30f6400c9ab11151d1cb95d73518bf776f31e54a64aa6b17d0e548abb54048bb4e4446395a1b7e71b6d2f145b81ab18adf834ded6ba0f
7
- data.tar.gz: 10d6820a08203cbac614de06c54f482b9beea538a73d0d9fa31543a43150cb8183552d52a7ae58a9bd4a82299edb2f807e7f8deb400060e0675c2c37e71c9534
6
+ metadata.gz: aae6977f6e8664bb8fb716a28f90be6a6a6ddc5a35a14bb3c9fc9cb0ba54b91847989b36911d03d299e07b04c2e55494f07fb387ccc8bffc494d954c19194c39
7
+ data.tar.gz: f156ba183d35d9825d85ff949cda127d702f84b7a878a6efae3edc73c901235c89731cdb1435f72623131c42c463ecd0ced1475674a3741c80ab1e8ca4d002db
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
- ## [0.1.0] - [TBD]
1
+ ## v0.1.2 - Aug 16, 2024
2
2
 
3
- - Initial release
3
+ Support for resetting contact properties with `nil`.
4
+
5
+ ## v0.1.1 - Aug 16, 2024
6
+
7
+ Added `ApiKey.test` method for testing API keys.
8
+
9
+ ## v0.1.0 - Aug 16, 2024
10
+
11
+ Initial release.
data/README.md CHANGED
@@ -6,29 +6,31 @@ This is the official Ruby SDK for [Loops](https://loops.so), an email platform f
6
6
 
7
7
  ## Installation
8
8
 
9
- Install the gem and add to the application's Gemfile by executing:
9
+ Install the gem and add it to the application's Gemfile like this:
10
10
 
11
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
11
+ ```bash
12
+ bundle add loops_sdk
13
+ ```
12
14
 
13
- If bundler is not being used to manage dependencies, install the gem by executing:
15
+ If bundler is not being used to manage dependencies, you can install the gem like this:
14
16
 
15
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
17
+ ```bash
18
+ gem install loops_sdk
19
+ ```
16
20
 
17
21
  ## Usage
18
22
 
19
23
  You will need a Loops API key to use the package.
20
24
 
21
- In your Loops account, go to the [API Settings page](https://app.loops.so/settings?page=api) and click "Generate key".
25
+ In your Loops account, go to the [API Settings page](https://app.loops.so/settings?page=api) and click **Generate key**.
22
26
 
23
- Copy this key and save it in your application code (for example as `LOOPS_API_KEY` in an `.env` file).
27
+ Copy this key and save it in your application code (for example, in an environment variable).
24
28
 
25
29
  See the API documentation to learn more about [rate limiting](https://loops.so/docs/api-reference#rate-limiting) and [error handling](https://loops.so/docs/api-reference#debugging).
26
30
 
27
31
  In an initializer, import and configure the SDK:
28
32
 
29
- ```ruby
30
- # config/initializers/loops.rb
31
-
33
+ ```ruby config/initializers/loops.rb
32
34
  require "loops_sdk"
33
35
 
34
36
  LoopsSdk.configure do |config|
@@ -54,6 +56,501 @@ rescue LoopsSdk::APIError => e
54
56
  end
55
57
  ```
56
58
 
59
+ ## Default contact properties
60
+
61
+ Each contact in Loops has a set of default properties. These will always be returned in API results.
62
+
63
+ - `id`
64
+ - `email`
65
+ - `firstName`
66
+ - `lastName`
67
+ - `source`
68
+ - `subscribed`
69
+ - `userGroup`
70
+ - `userId`
71
+
72
+ ## Custom contact properties
73
+
74
+ You can use custom contact properties in API calls. Please make sure to [add custom properties](https://loops.so/docs/contacts/properties#custom-contact-properties) in your Loops account before using them with the SDK.
75
+
76
+ ## Methods
77
+
78
+ - [ApiKey.test()](#apikey-test)
79
+ - [Contacts.create()](#contacts-create)
80
+ - [Contacts.update()](#contacts-update)
81
+ - [Contacts.find()](#contacts-find)
82
+ - [Contacts.delete()](#contacts-delete)
83
+ - [MailingLists.list()](#mailinglists-list)
84
+ - [Events.send()](#events-send)
85
+ - [Transactional.send()](#transactional-send)
86
+ - [CustomFields.list()](#customfields-list)
87
+
88
+ ---
89
+
90
+ ### ApiKey.test()
91
+
92
+ Test if your API key is valid.
93
+
94
+ [API Reference](https://loops.so/docs/api-reference/api-key)
95
+
96
+ #### Parameters
97
+
98
+ None
99
+
100
+ #### Example
101
+
102
+ ```ruby
103
+ response LoopsSdk::ApiKey.test
104
+ ```
105
+
106
+ #### Response
107
+
108
+ This method will return a success or error message:
109
+
110
+ ```json
111
+ {
112
+ "success": true,
113
+ "teamName": "Company name"
114
+ }
115
+ ```
116
+
117
+ ```json
118
+ {
119
+ "error": "Invalid API key"
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Contacts.create()
126
+
127
+ Create a new contact.
128
+
129
+ [API Reference](https://loops.so/docs/api-reference/create-contact)
130
+
131
+ #### Parameters
132
+
133
+ | Name | Type | Required | Notes |
134
+ | --------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
135
+ | `email` | string | Yes | If a contact already exists with this email address, an error response will be returned. |
136
+ | `properties` | object | No | An object containing default and any custom properties for your contact.<br />Please [add custom properties](https://loops.so/docs/contacts/properties#custom-contact-properties) in your Loops account before using them with the SDK.<br />Values can be of type `string`, `number`, `nil` (to reset a value), `boolean` or `date` ([see allowed date formats](https://loops.so/docs/contacts/properties#dates)). |
137
+ | `mailing_lists` | object | No | An object of mailing list IDs and boolean subscription statuses. |
138
+
139
+ #### Examples
140
+
141
+ ```ruby
142
+ response = LoopsSdk::Contacts.create(email: "hello@gmail.com")
143
+
144
+ contact_properties = {
145
+ firstName: "Bob" /* Default property */,
146
+ favoriteColor: "Red" /* Custom property */,
147
+ };
148
+ mailing_lists = {
149
+ list_123: true,
150
+ list_456: false,
151
+ };
152
+ response = LoopsSdk::Contacts.create(
153
+ email: "hello@gmail.com",
154
+ properties: contact_properties,
155
+ mailing_lists: mailing_lists
156
+ )
157
+ ```
158
+
159
+ #### Response
160
+
161
+ This method will return a success or error message:
162
+
163
+ ```json
164
+ {
165
+ "success": true,
166
+ "id": "id_of_contact"
167
+ }
168
+ ```
169
+
170
+ ```json
171
+ {
172
+ "success": false,
173
+ "message": "An error message here."
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Contacts.update()
180
+
181
+ Update a contact.
182
+
183
+ Note: To update a contact's email address, the contact requires a `userId` value. Then you can make a request with their `userId` and an updated email address.
184
+
185
+ [API Reference](https://loops.so/docs/api-reference/update-contact)
186
+
187
+ #### Parameters
188
+
189
+ | Name | Type | Required | Notes |
190
+ | --------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
191
+ | `email` | string | Yes | The email address of the contact to update. If there is no contact with this email address, a new contact will be created using the email and properties in this request. |
192
+ | `properties` | object | No | An object containing default and any custom properties for your contact.<br />Please [add custom properties](https://loops.so/docs/contacts/properties#custom-contact-properties) in your Loops account before using them with the SDK.<br />Values can be of type `string`, `number`, `nil` (to reset a value), `boolean` or `date` ([see allowed date formats](https://loops.so/docs/contacts/properties#dates)). |
193
+ | `mailing_lists` | object | No | An object of mailing list IDs and boolean subscription statuses. |
194
+
195
+ #### Example
196
+
197
+ ```ruby
198
+ contact_properties = {
199
+ firstName: "Bob" /* Default property */,
200
+ favoriteColor: "Blue" /* Custom property */,
201
+ };
202
+ response = LoopsSdk::Contacts.update(
203
+ email: "hello@gmail.com",
204
+ properties: contact_properties
205
+ )
206
+
207
+ # Updating a contact's email address using userId
208
+ response = LoopsSdk::Contacts.update(
209
+ email: "newemail@gmail.com",
210
+ properties: {
211
+ userId: "1234",
212
+ })
213
+ ```
214
+
215
+ #### Response
216
+
217
+ This method will return a success or error message:
218
+
219
+ ```json
220
+ {
221
+ "success": true,
222
+ "id": "id_of_contact"
223
+ }
224
+ ```
225
+
226
+ ```json
227
+ {
228
+ "success": false,
229
+ "message": "An error message here."
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ### Contacts.find()
236
+
237
+ Find a contact.
238
+
239
+ [API Reference](https://loops.so/docs/api-reference/find-contact)
240
+
241
+ #### Parameters
242
+
243
+ You must use one parameter in the request.
244
+
245
+ | Name | Type | Required | Notes |
246
+ | --------- | ------ | -------- | ----- |
247
+ | `email` | string | No | |
248
+ | `user_id` | string | No | |
249
+
250
+ #### Examples
251
+
252
+ ```ruby
253
+ response = LoopsSdk::Contacts.find(email: "hello@gmail.com")
254
+
255
+ response = LoopsSdk::Contacts.find(userId: "12345")
256
+ ```
257
+
258
+ #### Response
259
+
260
+ This method will return a list containing a single contact object, which will include all default properties and any custom properties.
261
+
262
+ If no contact is found, an empty list will be returned.
263
+
264
+ ```json
265
+ [
266
+ {
267
+ "id": "cll6b3i8901a9jx0oyktl2m4u",
268
+ "email": "hello@gmail.com",
269
+ "firstName": "Bob",
270
+ "lastName": null,
271
+ "source": "API",
272
+ "subscribed": true,
273
+ "userGroup": "",
274
+ "userId": "12345",
275
+ "favoriteColor": "Blue" /* Custom property */
276
+ }
277
+ ]
278
+ ```
279
+
280
+ ---
281
+
282
+ ### Contacts.delete()
283
+
284
+ Delete a contact, either by email address or `userId`.
285
+
286
+ [API Reference](https://loops.so/docs/api-reference/delete-contact)
287
+
288
+ #### Parameters
289
+
290
+ You must use one parameter in the request.
291
+
292
+ | Name | Type | Required | Notes |
293
+ | --------- | ------ | -------- | ----- |
294
+ | `email` | string | No | |
295
+ | `user_id` | string | No | |
296
+
297
+ #### Example
298
+
299
+ ```ruby
300
+ response = LoopsSdk::Contacts.delete(email: "hello@gmail.com")
301
+
302
+ response = LoopsSdk::Contacts.delete(userId: "12345")
303
+ ```
304
+
305
+ #### Response
306
+
307
+ This method will return a success or error message:
308
+
309
+ ```json
310
+ {
311
+ "success": true,
312
+ "message": "Contact deleted."
313
+ }
314
+ ```
315
+
316
+ ```json
317
+ {
318
+ "success": false,
319
+ "message": "An error message here."
320
+ }
321
+ ```
322
+
323
+ ---
324
+
325
+ ### MailingLists.list()
326
+
327
+ Get a list of your account's mailing lists. [Read more about mailing lists](https://loops.so/docs/contacts/mailing-lists)
328
+
329
+ [API Reference](https://loops.so/docs/api-reference/list-mailing-lists)
330
+
331
+ #### Parameters
332
+
333
+ None
334
+
335
+ #### Example
336
+
337
+ ```ruby
338
+ response = LoopsSdk::MailingLists.list
339
+ ```
340
+
341
+ #### Response
342
+
343
+ This method will return a list of mailing list objects containing `id` and `name` attributes.
344
+
345
+ If your account has no mailing lists, an empty list will be returned.
346
+
347
+ ```json
348
+ [
349
+ {
350
+ "id": "list_123",
351
+ "name": "Main list"
352
+ },
353
+ {
354
+ "id": "list_456",
355
+ "name": "Investors"
356
+ }
357
+ ]
358
+ ```
359
+
360
+ ---
361
+
362
+ ### Events.send()
363
+
364
+ Send an event to trigger an email in Loops. [Read more about events](https://loops.so/docs/events)
365
+
366
+ [API Reference](https://loops.so/docs/api-reference/send-event)
367
+
368
+ #### Parameters
369
+
370
+ | Name | Type | Required | Notes |
371
+ | -------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
372
+ | `event_name` | string | Yes | |
373
+ | `email` | string | No | The contact's email address. Required if `user_id` is not present. |
374
+ | `user_id` | string | No | The contact's unique user ID. If you use `user_id` without `email`, this value must have already been added to your contact in Loops. Required if `email` is not present. |
375
+ | `contact_properties` | object | No | An object containing contact properties, which will be updated or added to the contact when the event is received.<br />Please [add custom properties](https://loops.so/docs/contacts/properties#custom-contact-properties) in your Loops account before using them with the SDK.<br />Values can be of type `string`, `number`, `nil` (to reset a value), `boolean` or `date` ([see allowed date formats](https://loops.so/docs/contacts/properties#dates)). |
376
+ | `event_properties` | object | No | An object containing event properties, which will be made available in emails that are triggered by this event.<br />Values can be of type `string`, `number`, `boolean` or `date` ([see allowed date formats](https://loops.so/docs/events/properties#important-information-about-event-properties)). |
377
+ | `mailing_lists` | object | No | An object of mailing list IDs and boolean subscription statuses. |
378
+
379
+ #### Examples
380
+
381
+ ```ruby
382
+ response = LoopsSdk::Events.send(
383
+ event_name: "signup",
384
+ email: "hello@gmail.com"
385
+ )
386
+
387
+ response = LoopsSdk::Events.send(
388
+ event_name: "signup",
389
+ email: "hello@gmail.com",
390
+ event_properties: {
391
+ username: "user1234",
392
+ signupDate: "2024-03-21T10:09:23Z",
393
+ },
394
+ mailing_lists: {
395
+ list_123: true,
396
+ list_456: false,
397
+ },
398
+ })
399
+
400
+ # In this case with both email and userId present, the system will look for a contact with either a
401
+ # matching `email` or `user_id` value.
402
+ # If a contact is found for one of the values (e.g. `email`), the other value (e.g. `user_id`) will be updated.
403
+ # If a contact is not found, a new contact will be created using both `email` and `user_id` values.
404
+ # Any values added in `contact_properties` will also be updated on the contact.
405
+ response = LoopsSdk::Events.send(
406
+ event_name: "signup",
407
+ email: "hello@gmail.com",
408
+ user_id: "1234567890",
409
+ contact_properties: {
410
+ firstName: "Bob",
411
+ plan: "pro",
412
+ },
413
+ })
414
+ ```
415
+
416
+ #### Response
417
+
418
+ This method will return a success or error:
419
+
420
+ ```json
421
+ {
422
+ "success": true
423
+ }
424
+ ```
425
+
426
+ ```json
427
+ {
428
+ "success": false,
429
+ "message": "An error message here."
430
+ }
431
+ ```
432
+
433
+ ---
434
+
435
+ ### Transactional.send()
436
+
437
+ Send a transactional email to a contact. [Learn about sending transactional email](https://loops.so/docs/transactional/guide)
438
+
439
+ [API Reference](https://loops.so/docs/api-reference/send-transactional-email)
440
+
441
+ #### Parameters
442
+
443
+ | Name | Type | Required | Notes |
444
+ | ---------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
445
+ | `transactional_id` | string | Yes | The ID of the transactional email to send. |
446
+ | `email` | string | Yes | The email address of the recipient. |
447
+ | `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). |
448
+ | `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`. |
449
+ | `attachments` | object[] | No | A list of attachments objects.<br />**Please note**: Attachments need to be enabled on your account before using them with the API. [Read more](https://loops.so/docs/transactional/attachments) |
450
+ | `attachments[].filename` | string | No | The name of the file, shown in email clients. |
451
+ | `attachments[].content_type` | string | No | The MIME type of the file. |
452
+ | `attachments[].data` | string | No | The base64-encoded content of the file. |
453
+
454
+ #### Examples
455
+
456
+ ```ruby
457
+ response = LoopsSdk::Transactional.send(
458
+ transactional_id: "clfq6dinn000yl70fgwwyp82l",
459
+ email: "hello@gmail.com",
460
+ data_variables: {
461
+ loginUrl: "https://myapp.com/login/",
462
+ },
463
+ )
464
+
465
+ # Please contact us to enable attachments on your account.
466
+ response = LoopsSdk::Transactional.send(
467
+ transactional_id: "clfq6dinn000yl70fgwwyp82l",
468
+ email: "hello@gmail.com",
469
+ data_variables: {
470
+ loginUrl: "https://myapp.com/login/",
471
+ },
472
+ attachments: [
473
+ {
474
+ filename: "presentation.pdf",
475
+ content_type: "application/pdf",
476
+ data: "JVBERi0xLjMKJcTl8uXrp/Og0MTGCjQgMCBvYmoKPD...",
477
+ },
478
+ ],
479
+ })
480
+ ```
481
+
482
+ #### Response
483
+
484
+ This method will return a success or error message.
485
+
486
+ ```json
487
+ {
488
+ "success": true
489
+ }
490
+ ```
491
+
492
+ If there is a problem with the request, a descriptive error message will be returned:
493
+
494
+ ```json
495
+ {
496
+ "success": false,
497
+ "path": "dataVariables",
498
+ "message": "There are required fields for this email. You need to include a 'dataVariables' object with the required fields."
499
+ }
500
+ ```
501
+
502
+ ```json
503
+ {
504
+ "success": false,
505
+ "error": {
506
+ "path": "dataVariables",
507
+ "message": "Missing required fields: login_url"
508
+ },
509
+ "transactionalId": "clfq6dinn000yl70fgwwyp82l"
510
+ }
511
+ ```
512
+
513
+ ---
514
+
515
+ ### CustomFields.list()
516
+
517
+ Get a list of your account's custom fields. These are custom properties that can be added to contacts to store extra data. [Read more about contact properties](https://loops.so/docs/contacts/properties)
518
+
519
+ [API Reference](https://loops.so/docs/api-reference/list-custom-fields)
520
+
521
+ #### Parameters
522
+
523
+ None
524
+
525
+ #### Example
526
+
527
+ ```ruby
528
+ response LoopsSdk::CustomFields.list
529
+ ```
530
+
531
+ #### Response
532
+
533
+ This method will return a list of custom field objects containing `key`, `label` and `type` attributes.
534
+
535
+ If your account has no custom fields, an empty list will be returned.
536
+
537
+ ```json
538
+ [
539
+ {
540
+ "key": "favoriteColor",
541
+ "label": "Favorite Color",
542
+ "type": "string"
543
+ },
544
+ {
545
+ "key": "plan",
546
+ "label": "Plan",
547
+ "type": "string"
548
+ }
549
+ ]
550
+ ```
551
+
552
+ ---
553
+
57
554
  ## Contributing
58
555
 
59
556
  Bug reports and pull requests are welcome on GitHub at https://github.com/Loops-so/loops-rb.
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LoopsSdk
4
+ class ApiKey < Base
5
+ class << self
6
+ def test
7
+ make_request(:get, "v1/api-key")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -7,7 +7,7 @@ module LoopsSdk
7
7
  contact_data = {
8
8
  email: email,
9
9
  mailingLists: mailing_lists
10
- }.merge(properties.compact).compact
10
+ }.merge(properties)
11
11
  make_request(:post, "v1/contacts/create", {}, contact_data)
12
12
  end
13
13
 
@@ -15,7 +15,8 @@ module LoopsSdk
15
15
  contact_data = {
16
16
  email: email,
17
17
  mailingLists: mailing_lists
18
- }.merge(properties.compact).compact
18
+ }.merge(properties)
19
+ puts "Contact Data: #{contact_data.inspect}"
19
20
  make_request(:put, "v1/contacts/update", {}, contact_data)
20
21
  end
21
22
 
@@ -4,7 +4,7 @@ module LoopsSdk
4
4
  class CustomFields < Base
5
5
  class << self
6
6
  def list
7
- make_request(:get, "v1/customFields")
7
+ make_request(:get, "v1/contacts/customFields")
8
8
  end
9
9
  end
10
10
  end
@@ -12,7 +12,7 @@ module LoopsSdk
12
12
  eventName: event_name,
13
13
  eventProperties: event_properties.compact,
14
14
  mailingLists: mailing_lists.compact
15
- }.merge(contact_properties.compact).compact
15
+ }.merge(contact_properties)
16
16
  make_request(:post, "v1/events/send", {}, event_data)
17
17
  end
18
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LoopsSdk
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/loops_sdk.rb CHANGED
@@ -10,6 +10,7 @@ require_relative "loops_sdk/events"
10
10
  require_relative "loops_sdk/mailing_lists"
11
11
  require_relative "loops_sdk/transactional"
12
12
  require_relative "loops_sdk/custom_fields"
13
+ require_relative "loops_sdk/api_key"
13
14
 
14
15
  module LoopsSdk
15
16
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loops_sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Rowden
@@ -37,6 +37,7 @@ files:
37
37
  - README.md
38
38
  - Rakefile
39
39
  - lib/loops_sdk.rb
40
+ - lib/loops_sdk/api_key.rb
40
41
  - lib/loops_sdk/base.rb
41
42
  - lib/loops_sdk/configuration.rb
42
43
  - lib/loops_sdk/contacts.rb