mailerlite-ruby 2.0.0 → 2.1.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/.envrc +2 -0
- data/.github/workflows/main.yml +1 -1
- data/.github/workflows/publish_gem.yml +1 -1
- data/.gitignore +2 -1
- data/CHANGELOG.md +17 -0
- data/README.md +574 -0
- data/flake.lock +27 -0
- data/flake.nix +25 -0
- data/lefthook.yml +14 -0
- data/lib/mailerlite/api_response.rb +24 -0
- data/lib/mailerlite/automations/automation_emails.rb +57 -0
- data/lib/mailerlite/automations/automation_reports.rb +114 -0
- data/lib/mailerlite/automations/automation_steps.rb +105 -0
- data/lib/mailerlite/automations/automation_templates.rb +34 -0
- data/lib/mailerlite/automations/automation_triggers.rb +62 -0
- data/lib/mailerlite/automations/automations.rb +177 -8
- data/lib/mailerlite/brand_styles/brand_styles.rb +24 -0
- data/lib/mailerlite/campaigns/campaigns.rb +33 -1
- data/lib/mailerlite/ecommerce/ecommerce.rb +316 -0
- data/lib/mailerlite/emails/emails.rb +306 -0
- data/lib/mailerlite/errors.rb +88 -0
- data/lib/mailerlite/files/files.rb +45 -0
- data/lib/mailerlite/groups/groups.rb +16 -8
- data/lib/mailerlite/params.rb +58 -0
- data/lib/mailerlite/query_params.rb +33 -0
- data/lib/mailerlite/request.rb +24 -0
- data/lib/mailerlite/segments/segments.rb +10 -10
- data/lib/mailerlite/subscribers/subscribers.rb +63 -8
- data/lib/mailerlite/version.rb +1 -1
- data/lib/mailerlite.rb +14 -0
- data/spec/api_response_rspec.rb +140 -0
- data/spec/automation_emails_rspec.rb +40 -0
- data/spec/automation_reports_rspec.rb +92 -0
- data/spec/automation_steps_rspec.rb +76 -0
- data/spec/automation_templates_rspec.rb +24 -0
- data/spec/automation_triggers_rspec.rb +48 -0
- data/spec/automations_rspec.rb +143 -0
- data/spec/brand_styles_rspec.rb +49 -0
- data/spec/campaigns_rspec.rb +42 -0
- data/spec/ecommerce_rspec.rb +141 -0
- data/spec/emails_rspec.rb +692 -0
- data/spec/files_rspec.rb +90 -0
- data/spec/fixtures/brand_styles.json +50 -0
- data/spec/fixtures/campaign_simple_editor.json +24 -0
- data/spec/fixtures/email.json +81 -0
- data/spec/fixtures/email_block.json +12 -0
- data/spec/fixtures/email_block_created.json +12 -0
- data/spec/fixtures/email_block_created_rejected.json +15 -0
- data/spec/fixtures/email_block_moved.json +12 -0
- data/spec/fixtures/email_block_updated.json +9 -0
- data/spec/fixtures/email_block_updated_rejected.json +13 -0
- data/spec/fixtures/email_block_validation_invalid.json +5 -0
- data/spec/fixtures/email_etag.json +1 -0
- data/spec/fixtures/email_html.json +1 -0
- data/spec/fixtures/email_settings.json +111 -0
- data/spec/fixtures/email_settings_validation.json +9 -0
- data/spec/fixtures/email_template.json +1 -0
- data/spec/fixtures/email_version.json +1 -0
- data/spec/fixtures/email_versions.json +26 -0
- data/spec/fixtures/files.json +44 -0
- data/spec/groups_rspec.rb +21 -0
- data/spec/params_rspec.rb +126 -0
- data/spec/request_rspec.rb +139 -0
- data/spec/segments_rspec.rb +39 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/subscribers_rspec.rb +57 -0
- data/spec/support/json_fixture.rb +27 -0
- data/spec/support/request_stub.rb +25 -0
- metadata +54 -7
- /data/{renovate.json → .github/renovate.json} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b288c8921cc1a4959ec479db44ccc5c79596d59f0dff01db290d10bee0d8bccc
|
|
4
|
+
data.tar.gz: b53dca35235a46e10fca946eeb8ac59a2f49136eaf3deb45d20b56531ec6ba7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd2c3f01b1bb5741f1972631c079224c063c3ead57739a321482ca8a66e66cbce52907e2d05c8b30a64b6d1392f6999f61ce4b3d0c935a503a24d12212ffc690
|
|
7
|
+
data.tar.gz: 309fecb3615cdd5d2c9b3f0f5d344b024440f6cbde0a36ac7c02754f59052f080a826067d9aab80c65dd43e7efe3ba69f0179eacbd3ebfe67d2857ff69520397
|
data/.envrc
ADDED
data/.github/workflows/main.yml
CHANGED
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
- Add `Automations#create`, `#update`, `#delete`, `#copy`, `#enable`, `#disable`, `#test`, `#add_subscribers`, `#readd`, `#add_activity_to_group`, `#cancel_activity` and `#skip_activity_delay`
|
|
3
|
+
- Add the `AutomationTriggers`, `AutomationSteps`, `AutomationEmails`, `AutomationTemplates` and `AutomationReports` classes
|
|
4
|
+
- Add `Subscribers#activity_log` and `Groups#import_subscribers`
|
|
5
|
+
- Add the missing documented params to `Subscribers#fetch`, `Subscribers#create`, `Groups#get_subscribers`, `Segments#list`, `Segments#update` and `Automations#get`
|
|
6
|
+
- `Segments#get_subscribers` takes `cursor`. The API ignores `after`, so it always returned the first page
|
|
7
|
+
- `Groups#get_subscribers` and `Segments#list` send their params in the query string, not in a JSON body on a GET
|
|
8
|
+
- `Automations#get_subscriber_activity` takes `filter[:search]`, sent as `filter[search]`. The old `filter[:keyword]` is now sent as `filter[search]` too; the API rejected `filter[keyword]` with a 400
|
|
9
|
+
- `AutomationReports#step_subscribers` and `#trigger_subscribers` send an Array `filter[:id]` as one comma-separated value
|
|
10
|
+
- `Automations#get_subscriber_activity` takes `with_subscribers: true` to include each run's subscriber. It sends `with_subscribers=1` only when true, because the API turns it on for any value
|
|
11
|
+
- Add the `Emails` class for the emails built with the simple editor: get an email, its HTML and its blocks, insert, update, delete, move and validate blocks, update and validate the design settings, save a template, and list, save and restore versions
|
|
12
|
+
- Add `BrandStyles#get` and `Files#list`
|
|
13
|
+
- Add `Campaigns::EDITOR_SIMPLE`, and document `editor` and `template_id` for the emails of `Campaigns#create`
|
|
14
|
+
- Add the optional `idempotency_key` argument to the email writes
|
|
15
|
+
- The new methods return an `HTTP::Response` with `api_error` (a `MailerLite::ApiError` with `status`, `code`, `etag`, `errors` and `api_message`) and `idempotent_replay?`. They do not raise for an API error
|
|
16
|
+
- Document `rejected` in the responses of `Emails#create_block`, `#update_block` and `#validate_block`: the keys that the API dropped from the block
|
|
17
|
+
|
|
1
18
|
## [2.0.0] - 2024-12-11
|
|
2
19
|
- *BREAKING CHANGE* - Please check the README file, dotenv is now optional
|
|
3
20
|
- *BREAKING CHANGE* - Updated the minimal required Ruby version from 2.5 to 3.1
|
data/README.md
CHANGED
|
@@ -55,11 +55,32 @@ For more information how to obtain an API key visit the [following link](https:/
|
|
|
55
55
|
- [List all campaigns](#list-all-campaigns)
|
|
56
56
|
- [Get a campaign](#get-a-campaign)
|
|
57
57
|
- [Create a campaign](#create-a-campaign)
|
|
58
|
+
- [Create a campaign with the simple editor](#create-a-campaign-with-the-simple-editor)
|
|
58
59
|
- [Update a campaign](#update-a-campaign)
|
|
59
60
|
- [Schedule a campaign](#schedule-a-campaign)
|
|
60
61
|
- [Cancel a campaign](#cancel-a-campaign)
|
|
61
62
|
- [Delete a campaign](#delete-a-campaign)
|
|
62
63
|
- [Get subscribers activity for a campaign](#get-subscribers-activity-for-a-campaign)
|
|
64
|
+
- [Emails](#emails)
|
|
65
|
+
- [Get an email](#get-an-email)
|
|
66
|
+
- [Get the HTML of an email](#get-the-html-of-an-email)
|
|
67
|
+
- [Get a block](#get-a-block)
|
|
68
|
+
- [Insert a block](#insert-a-block)
|
|
69
|
+
- [Update a block](#update-a-block)
|
|
70
|
+
- [Delete a block](#delete-a-block)
|
|
71
|
+
- [Move a block](#move-a-block)
|
|
72
|
+
- [Validate a block](#validate-a-block)
|
|
73
|
+
- [Update the design settings](#update-the-design-settings)
|
|
74
|
+
- [Validate the design settings](#validate-the-design-settings)
|
|
75
|
+
- [Save an email as a template](#save-an-email-as-a-template)
|
|
76
|
+
- [List the versions of an email](#list-the-versions-of-an-email)
|
|
77
|
+
- [Save a version of an email](#save-a-version-of-an-email)
|
|
78
|
+
- [Restore a version of an email](#restore-a-version-of-an-email)
|
|
79
|
+
- [Retry a write with an idempotency key](#retry-a-write-with-an-idempotency-key)
|
|
80
|
+
- [Brand styles](#brand-styles)
|
|
81
|
+
- [Get the brand styles](#get-the-brand-styles)
|
|
82
|
+
- [Files](#files)
|
|
83
|
+
- [List all files](#list-all-files)
|
|
63
84
|
- [Forms](#forms)
|
|
64
85
|
- [List all forms](#list-all-forms)
|
|
65
86
|
- [Get a form](#get-a-form)
|
|
@@ -78,6 +99,13 @@ For more information how to obtain an API key visit the [following link](https:/
|
|
|
78
99
|
- [Get a list of timezones](#get-a-list-of-timezones)
|
|
79
100
|
- [Campaign languages](#campaign-languages)
|
|
80
101
|
- [Get a list of languages](#get-a-list-of-languages)
|
|
102
|
+
- [E-commerce](#e-commerce)
|
|
103
|
+
- [Shops](#shops)
|
|
104
|
+
- [Products and variants](#products-and-variants)
|
|
105
|
+
- [Categories](#categories)
|
|
106
|
+
- [Customers, orders and carts](#customers-orders-and-carts)
|
|
107
|
+
- [Imports](#imports)
|
|
108
|
+
- [Revenue reports and settings](#revenue-reports-and-settings)
|
|
81
109
|
|
|
82
110
|
## Setup
|
|
83
111
|
|
|
@@ -480,6 +508,36 @@ campaigns.create(
|
|
|
480
508
|
)
|
|
481
509
|
```
|
|
482
510
|
|
|
511
|
+
### Create a campaign with the simple editor
|
|
512
|
+
|
|
513
|
+
<a name="create-a-campaign-with-the-simple-editor"></a>
|
|
514
|
+
|
|
515
|
+
To build the email with the simple editor, set `editor` to `MailerLite::Campaigns::EDITOR_SIMPLE`, and do not send `content`. Then edit the email with [the email methods](#emails).
|
|
516
|
+
|
|
517
|
+
- `template_id` is optional. It is the simple editor template that the email starts from: a template from the shared gallery, or a template that you saved from your own email with [`create_template`](#save-an-email-as-a-template) (the `id` in its response). It needs `editor`. Without it, the email starts from the default blank template. The API copies the template into the new email and does not change the template.
|
|
518
|
+
- All emails of a campaign must have the same `editor` and `template_id`.
|
|
519
|
+
- Only `create` accepts `editor` and `template_id`. `update` does not.
|
|
520
|
+
|
|
521
|
+
```ruby
|
|
522
|
+
require "mailerlite-ruby"
|
|
523
|
+
|
|
524
|
+
# Initialize the class
|
|
525
|
+
campaigns = MailerLite::Campaigns.new
|
|
526
|
+
|
|
527
|
+
response = campaigns.create(
|
|
528
|
+
name: "Test Campaign",
|
|
529
|
+
type: "regular",
|
|
530
|
+
emails: [{
|
|
531
|
+
subject: "This is a test campaign",
|
|
532
|
+
from_name: "Test Man",
|
|
533
|
+
from: "testuser@mailerlite.com",
|
|
534
|
+
editor: MailerLite::Campaigns::EDITOR_SIMPLE
|
|
535
|
+
}]
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
email_id = JSON.parse(response.body)['data']['emails'][0]['id']
|
|
539
|
+
```
|
|
540
|
+
|
|
483
541
|
### Update a campaign
|
|
484
542
|
|
|
485
543
|
<a name="update-a-campaign"></a>
|
|
@@ -569,6 +627,408 @@ campaign_id = 123456
|
|
|
569
627
|
campaigns.activity(campaign_id)
|
|
570
628
|
```
|
|
571
629
|
|
|
630
|
+
## Emails
|
|
631
|
+
|
|
632
|
+
<a name="emails"></a>
|
|
633
|
+
|
|
634
|
+
These methods edit emails built with the simple editor. To create such an email, [create a campaign with the simple editor](#create-a-campaign-with-the-simple-editor). The ID of the email is in `data.emails[0].id` of the response.
|
|
635
|
+
|
|
636
|
+
- IDs are strings of digits. You can also give them as integers. An empty ID raises `MailerLite::EmptyIdError`, and an ID that does not contain only digits raises `MailerLite::InvalidIdError`. The SDK sends no request in these cases.
|
|
637
|
+
- The SDK checks only the IDs in the URL path, and the settings of `update_settings`: they must be a Hash without an `etag` key. The SDK sends all other values as you give them, and the API checks them. For a value that is not valid, the API returns `422` with the `errors` for each field.
|
|
638
|
+
- The methods return an `HTTP::Response`, like the other methods. Use `response.code` for the status code, `response.headers` for the headers and `JSON.parse(response.body)` for the body.
|
|
639
|
+
- The methods do not raise an error for a `4xx` or `5xx` status. `response.api_error` is `nil` for a `2xx` status. For other statuses, it is a `MailerLite::ApiError` with `status`, `code`, `etag`, `api_message` and `errors`. You can raise it.
|
|
640
|
+
- Each write needs the etag from the last response for the email, and returns a new etag. The etag covers the whole email, so send the writes to one email one after another.
|
|
641
|
+
- If the email changed after you read it, the write returns `409`, and `response.api_error.code` is `MailerLite::Emails::VERSION_CONFLICT`. Then `response.api_error.etag` is the current etag. Get the email again, and then send the write again with the current etag.
|
|
642
|
+
- The keys of `editor_content` are camelCase, for example `textAlign`. The SDK sends them as you give them.
|
|
643
|
+
|
|
644
|
+
### Get an email
|
|
645
|
+
|
|
646
|
+
<a name="get-an-email"></a>
|
|
647
|
+
|
|
648
|
+
Returns the email with its settings and blocks, and the etag of the email.
|
|
649
|
+
|
|
650
|
+
```ruby
|
|
651
|
+
require "mailerlite-ruby"
|
|
652
|
+
|
|
653
|
+
# Initialize the class
|
|
654
|
+
emails = MailerLite::Emails.new
|
|
655
|
+
|
|
656
|
+
response = emails.get('123456')
|
|
657
|
+
|
|
658
|
+
body = JSON.parse(response.body)
|
|
659
|
+
email = body['data']
|
|
660
|
+
etag = body['etag']
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Get the HTML of an email
|
|
664
|
+
|
|
665
|
+
<a name="get-the-html-of-an-email"></a>
|
|
666
|
+
|
|
667
|
+
Returns the HTML that the email sends. The API can return a temporary `503` error. If it does, try again later.
|
|
668
|
+
|
|
669
|
+
```ruby
|
|
670
|
+
require "mailerlite-ruby"
|
|
671
|
+
|
|
672
|
+
# Initialize the class
|
|
673
|
+
emails = MailerLite::Emails.new
|
|
674
|
+
|
|
675
|
+
response = emails.get_html('123456')
|
|
676
|
+
|
|
677
|
+
html = JSON.parse(response.body)['data']['html'] if response.code == 200
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
### Get a block
|
|
681
|
+
|
|
682
|
+
<a name="get-a-block"></a>
|
|
683
|
+
|
|
684
|
+
Returns the block and its place in the email: `placement` has the IDs of the blocks `after` and `before` it, or `nil`.
|
|
685
|
+
|
|
686
|
+
```ruby
|
|
687
|
+
require "mailerlite-ruby"
|
|
688
|
+
|
|
689
|
+
# Initialize the class
|
|
690
|
+
emails = MailerLite::Emails.new
|
|
691
|
+
|
|
692
|
+
response = emails.get_block(email_id: '123456', block_id: '57')
|
|
693
|
+
|
|
694
|
+
block = JSON.parse(response.body)['data']
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Insert a block
|
|
698
|
+
|
|
699
|
+
<a name="insert-a-block"></a>
|
|
700
|
+
|
|
701
|
+
Use the block types in `MailerLite::Emails::BlockType`. `editor_content` can be empty. Without `placement`, the API puts the block at the end of the email. The positions are in `MailerLite::Emails::BlockPosition`. The `BEFORE` and `AFTER` positions also need a `block_id`. The SDK sends `placement` as you give it.
|
|
702
|
+
|
|
703
|
+
The API drops the attributes and the `mobile` keys that the block type does not declare, and the write still succeeds. Then the response has `rejected` with a `message` and the `keys` that the API dropped, for example `editor_content.attrs.onclick`. When the API drops nothing, the response has no `rejected`.
|
|
704
|
+
|
|
705
|
+
```ruby
|
|
706
|
+
require "mailerlite-ruby"
|
|
707
|
+
|
|
708
|
+
# Initialize the class
|
|
709
|
+
emails = MailerLite::Emails.new
|
|
710
|
+
|
|
711
|
+
email_id = '123456'
|
|
712
|
+
etag = JSON.parse(emails.get(email_id).body)['etag']
|
|
713
|
+
|
|
714
|
+
response = emails.create_block(
|
|
715
|
+
email_id: email_id,
|
|
716
|
+
etag: etag,
|
|
717
|
+
type: MailerLite::Emails::BlockType::PARAGRAPH,
|
|
718
|
+
editor_content: { attrs: { textAlign: 'left' }, content: [{ type: 'text', text: 'Hello' }] },
|
|
719
|
+
placement: { position: MailerLite::Emails::BlockPosition::AT_START }
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
body = JSON.parse(response.body)
|
|
723
|
+
block_id = body['data']['id']
|
|
724
|
+
etag = body['etag']
|
|
725
|
+
puts body['rejected']['keys'] if body['rejected']
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
### Update a block
|
|
729
|
+
|
|
730
|
+
<a name="update-a-block"></a>
|
|
731
|
+
|
|
732
|
+
The new `editor_content` replaces the whole content of the block. The API removes the keys that you do not send.
|
|
733
|
+
|
|
734
|
+
The API drops the attributes and the `mobile` keys that the block type does not declare, and the write still succeeds. Then the response has `rejected` with a `message` and the `keys` that the API dropped, for example `editor_content.mobile.onclick`. When the API drops nothing, the response has no `rejected`.
|
|
735
|
+
|
|
736
|
+
```ruby
|
|
737
|
+
require "mailerlite-ruby"
|
|
738
|
+
|
|
739
|
+
# Initialize the class
|
|
740
|
+
emails = MailerLite::Emails.new
|
|
741
|
+
|
|
742
|
+
response = emails.update_block(
|
|
743
|
+
email_id: '123456',
|
|
744
|
+
block_id: '57',
|
|
745
|
+
etag: 'etag-from-the-last-response',
|
|
746
|
+
editor_content: { attrs: { textAlign: 'center' }, content: [{ type: 'text', text: 'Hello again' }] }
|
|
747
|
+
)
|
|
748
|
+
|
|
749
|
+
body = JSON.parse(response.body)
|
|
750
|
+
etag = body['etag']
|
|
751
|
+
puts body['rejected']['keys'] if body['rejected']
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
### Delete a block
|
|
755
|
+
|
|
756
|
+
<a name="delete-a-block"></a>
|
|
757
|
+
|
|
758
|
+
Also deletes the blocks in it. The response has only the new etag.
|
|
759
|
+
|
|
760
|
+
```ruby
|
|
761
|
+
require "mailerlite-ruby"
|
|
762
|
+
|
|
763
|
+
# Initialize the class
|
|
764
|
+
emails = MailerLite::Emails.new
|
|
765
|
+
|
|
766
|
+
response = emails.delete_block(email_id: '123456', block_id: '57', etag: 'etag-from-the-last-response')
|
|
767
|
+
|
|
768
|
+
etag = JSON.parse(response.body)['etag']
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
### Move a block
|
|
772
|
+
|
|
773
|
+
<a name="move-a-block"></a>
|
|
774
|
+
|
|
775
|
+
The `BEFORE` and `AFTER` positions also need a `block_id`. The SDK sends `placement` as you give it.
|
|
776
|
+
|
|
777
|
+
```ruby
|
|
778
|
+
require "mailerlite-ruby"
|
|
779
|
+
|
|
780
|
+
# Initialize the class
|
|
781
|
+
emails = MailerLite::Emails.new
|
|
782
|
+
|
|
783
|
+
response = emails.move_block(
|
|
784
|
+
email_id: '123456',
|
|
785
|
+
block_id: '57',
|
|
786
|
+
etag: 'etag-from-the-last-response',
|
|
787
|
+
placement: { position: MailerLite::Emails::BlockPosition::AFTER, block_id: '12' }
|
|
788
|
+
)
|
|
789
|
+
|
|
790
|
+
etag = JSON.parse(response.body)['etag']
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
### Validate a block
|
|
794
|
+
|
|
795
|
+
<a name="validate-a-block"></a>
|
|
796
|
+
|
|
797
|
+
Checks a block before you insert it. It needs no email and no etag. An invalid block is not an error: the response has `valid` set to `false` and the `errors` for each field.
|
|
798
|
+
|
|
799
|
+
If a valid block has attributes or `mobile` keys that the block type does not declare, the response has `rejected` with a `message` and these `keys`. Insert and update drop these keys. When `valid` is `false`, the response has no `rejected`.
|
|
800
|
+
|
|
801
|
+
The block in this example is not valid, because `sideways` is not a valid `textAlign`. The response has `valid: false` and `errors`.
|
|
802
|
+
|
|
803
|
+
```ruby
|
|
804
|
+
require "mailerlite-ruby"
|
|
805
|
+
|
|
806
|
+
# Initialize the class
|
|
807
|
+
emails = MailerLite::Emails.new
|
|
808
|
+
|
|
809
|
+
response = emails.validate_block(
|
|
810
|
+
type: MailerLite::Emails::BlockType::PARAGRAPH,
|
|
811
|
+
editor_content: { attrs: { textAlign: 'sideways' } }
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
body = JSON.parse(response.body)
|
|
815
|
+
puts body['errors'] unless body['valid']
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
### Update the design settings
|
|
819
|
+
|
|
820
|
+
<a name="update-the-design-settings"></a>
|
|
821
|
+
|
|
822
|
+
Send only the keys to change, in the shape of `settings` in the email. The groups are `brand`, `layout`, `typography`, `button` and `footer`.
|
|
823
|
+
|
|
824
|
+
- The SDK sends exactly the keys of the Hash. A key that is not in the Hash does not change.
|
|
825
|
+
- To unset a brand colour, send an empty string. The API stores the value empty, and the email then uses the account value.
|
|
826
|
+
- To unset a footer text, send an empty editor document: `{ editor_content: {} }` or `{ editor_content: { content: [] } }`.
|
|
827
|
+
- Other colours, sizes, `button.border_radius` and `brand.style` cannot be empty. An empty string gives a `422` error.
|
|
828
|
+
- Send all style values as strings, for example `'16'` and not `16`.
|
|
829
|
+
- The API stores each value that you send, also a value that the email inherits from your account. Then the email no longer follows your account for that value.
|
|
830
|
+
- `footer.social_links` replaces the whole list. Keep the `link_id` of each link to keep its click history.
|
|
831
|
+
- `brand.mode` is one of `MailerLite::Emails::BrandMode`. To apply a preset palette, send its `identifier` from the brand styles in `brand.style`.
|
|
832
|
+
- Do not put `etag` in the settings. Use the `etag` argument.
|
|
833
|
+
- If the API removed unsafe values, the response has `rejected` with the keys of these values.
|
|
834
|
+
|
|
835
|
+
```ruby
|
|
836
|
+
require "mailerlite-ruby"
|
|
837
|
+
|
|
838
|
+
# Initialize the class
|
|
839
|
+
emails = MailerLite::Emails.new
|
|
840
|
+
|
|
841
|
+
response = emails.update_settings(
|
|
842
|
+
email_id: '123456',
|
|
843
|
+
etag: 'etag-from-the-last-response',
|
|
844
|
+
settings: {
|
|
845
|
+
brand: { mode: MailerLite::Emails::BrandMode::CUSTOM, background_color: '#f4f4f4' },
|
|
846
|
+
typography: { paragraph: { p1: { size: '18' } } }
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
body = JSON.parse(response.body)
|
|
851
|
+
etag = body['etag']
|
|
852
|
+
puts body['rejected']['keys'] if body['rejected']
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
### Validate the design settings
|
|
856
|
+
|
|
857
|
+
<a name="validate-the-design-settings"></a>
|
|
858
|
+
|
|
859
|
+
Checks a change with the rules of the update, and saves nothing. It needs no etag. Invalid settings are not an error: the response has `valid` set to `false` and the `errors` for each field.
|
|
860
|
+
|
|
861
|
+
```ruby
|
|
862
|
+
require "mailerlite-ruby"
|
|
863
|
+
|
|
864
|
+
# Initialize the class
|
|
865
|
+
emails = MailerLite::Emails.new
|
|
866
|
+
|
|
867
|
+
response = emails.validate_settings(email_id: '123456', settings: { button: { border_radius: '8' } })
|
|
868
|
+
|
|
869
|
+
body = JSON.parse(response.body)
|
|
870
|
+
puts body['errors'] unless body['valid']
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Save an email as a template
|
|
874
|
+
|
|
875
|
+
<a name="save-an-email-as-a-template"></a>
|
|
876
|
+
|
|
877
|
+
Copies the email to a new template. The API cannot delete templates.
|
|
878
|
+
|
|
879
|
+
```ruby
|
|
880
|
+
require "mailerlite-ruby"
|
|
881
|
+
|
|
882
|
+
# Initialize the class
|
|
883
|
+
emails = MailerLite::Emails.new
|
|
884
|
+
|
|
885
|
+
response = emails.create_template(email_id: '123456', name: 'Monthly newsletter')
|
|
886
|
+
|
|
887
|
+
template_id = JSON.parse(response.body)['data']['id']
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
### List the versions of an email
|
|
891
|
+
|
|
892
|
+
<a name="list-the-versions-of-an-email"></a>
|
|
893
|
+
|
|
894
|
+
A version is a saved copy of the content and the settings of an email. The list starts with the newest version. `current` marks the version that the email has now.
|
|
895
|
+
|
|
896
|
+
```ruby
|
|
897
|
+
require "mailerlite-ruby"
|
|
898
|
+
|
|
899
|
+
# Initialize the class
|
|
900
|
+
emails = MailerLite::Emails.new
|
|
901
|
+
|
|
902
|
+
response = emails.list_versions('123456', page: 1, limit: 10)
|
|
903
|
+
|
|
904
|
+
versions = JSON.parse(response.body)['data']
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
### Save a version of an email
|
|
908
|
+
|
|
909
|
+
<a name="save-a-version-of-an-email"></a>
|
|
910
|
+
|
|
911
|
+
Writes through the API do not save versions. If nothing changed after the last version, the API saves no new version and returns the last version. `response.code` is `201` for a new version and `200` for the last version.
|
|
912
|
+
|
|
913
|
+
```ruby
|
|
914
|
+
require "mailerlite-ruby"
|
|
915
|
+
|
|
916
|
+
# Initialize the class
|
|
917
|
+
emails = MailerLite::Emails.new
|
|
918
|
+
|
|
919
|
+
response = emails.create_version('123456')
|
|
920
|
+
|
|
921
|
+
version_id = JSON.parse(response.body)['data']['id']
|
|
922
|
+
is_new = response.code == 201
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### Restore a version of an email
|
|
926
|
+
|
|
927
|
+
<a name="restore-a-version-of-an-email"></a>
|
|
928
|
+
|
|
929
|
+
Puts the email back to the version, and returns the full email with the new etag. Before the restore, the API saves the current state as a version, so you can undo the restore.
|
|
930
|
+
|
|
931
|
+
```ruby
|
|
932
|
+
require "mailerlite-ruby"
|
|
933
|
+
|
|
934
|
+
# Initialize the class
|
|
935
|
+
emails = MailerLite::Emails.new
|
|
936
|
+
|
|
937
|
+
response = emails.restore_version(email_id: '123456', version_id: '901', etag: 'etag-from-the-last-response')
|
|
938
|
+
|
|
939
|
+
etag = JSON.parse(response.body)['etag']
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
### Retry a write with an idempotency key
|
|
943
|
+
|
|
944
|
+
<a name="retry-a-write-with-an-idempotency-key"></a>
|
|
945
|
+
|
|
946
|
+
If a write fails with a network error, you do not know if the API did the write. Give the write an `idempotency_key`, and send it again with the same key and the same arguments. If the first request was a success, the API returns the stored response and does not do the write two times. Then `response.idempotent_replay?` is `true`.
|
|
947
|
+
|
|
948
|
+
- Use a new key for each write. The API keeps a key for 24 hours.
|
|
949
|
+
- The key must be 1 to 255 printable ASCII characters. The SDK sends the key as you give it. For a key that is not valid, the API returns `400`.
|
|
950
|
+
- The same key with different arguments returns `422`. If the first request is still running, the API returns `409` without a `code`.
|
|
951
|
+
- These methods accept a key: `create_block`, `update_block`, `delete_block`, `move_block`, `update_settings`, `create_template`, `create_version` and `restore_version`.
|
|
952
|
+
|
|
953
|
+
```ruby
|
|
954
|
+
require "mailerlite-ruby"
|
|
955
|
+
require "securerandom"
|
|
956
|
+
|
|
957
|
+
# Initialize the class
|
|
958
|
+
emails = MailerLite::Emails.new
|
|
959
|
+
|
|
960
|
+
args = {
|
|
961
|
+
email_id: '123456',
|
|
962
|
+
etag: 'etag-from-the-last-response',
|
|
963
|
+
type: MailerLite::Emails::BlockType::DIVIDER,
|
|
964
|
+
editor_content: {},
|
|
965
|
+
idempotency_key: SecureRandom.uuid
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
begin
|
|
969
|
+
response = emails.create_block(**args)
|
|
970
|
+
rescue HTTP::ConnectionError, HTTP::TimeoutError
|
|
971
|
+
# Network error: send the write again with the same key and the same arguments.
|
|
972
|
+
response = emails.create_block(**args)
|
|
973
|
+
end
|
|
974
|
+
|
|
975
|
+
error = response.api_error
|
|
976
|
+
raise error if error
|
|
977
|
+
|
|
978
|
+
puts JSON.parse(response.body)['data']['id'], response.idempotent_replay?
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
## Brand styles
|
|
982
|
+
|
|
983
|
+
<a name="brand-styles"></a>
|
|
984
|
+
|
|
985
|
+
### Get the brand styles
|
|
986
|
+
|
|
987
|
+
<a name="get-the-brand-styles"></a>
|
|
988
|
+
|
|
989
|
+
Returns the palettes of your account: `brand` (your brand styles, or `nil` if your account has none), `default` and the `presets`. Match a palette on its `identifier`, not on its `name`. To apply a preset to an email, [update the design settings](#update-the-design-settings) with `{ brand: { style: identifier } }`.
|
|
990
|
+
|
|
991
|
+
```ruby
|
|
992
|
+
require "mailerlite-ruby"
|
|
993
|
+
|
|
994
|
+
# Initialize the class
|
|
995
|
+
brand_styles = MailerLite::BrandStyles.new
|
|
996
|
+
|
|
997
|
+
response = brand_styles.get
|
|
998
|
+
|
|
999
|
+
identifiers = JSON.parse(response.body)['data']['presets'].map { |preset| preset['identifier'] }
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## Files
|
|
1003
|
+
|
|
1004
|
+
<a name="files"></a>
|
|
1005
|
+
|
|
1006
|
+
### List all files
|
|
1007
|
+
|
|
1008
|
+
<a name="list-all-files"></a>
|
|
1009
|
+
|
|
1010
|
+
Returns the files of your media library. Use their `url` in image blocks. `width` and `height` are `nil` for files that are not images.
|
|
1011
|
+
|
|
1012
|
+
- `filter`: `name` (a part of the file name) and `type` (one of `MailerLite::Files::FileType`).
|
|
1013
|
+
- `sort`: one of `MailerLite::Files::FileSort`. The default is newest first.
|
|
1014
|
+
- The SDK does not send `nil` values.
|
|
1015
|
+
|
|
1016
|
+
```ruby
|
|
1017
|
+
require "mailerlite-ruby"
|
|
1018
|
+
|
|
1019
|
+
# Initialize the class
|
|
1020
|
+
files = MailerLite::Files.new
|
|
1021
|
+
|
|
1022
|
+
response = files.list(
|
|
1023
|
+
filter: { name: 'summer sale', type: MailerLite::Files::FileType::IMAGE },
|
|
1024
|
+
sort: MailerLite::Files::FileSort::SIZE_DESC,
|
|
1025
|
+
page: 1,
|
|
1026
|
+
limit: 25
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
urls = JSON.parse(response.body)['data'].map { |file| file['url'] }
|
|
1030
|
+
```
|
|
1031
|
+
|
|
572
1032
|
## Forms
|
|
573
1033
|
|
|
574
1034
|
<a name="forms"></a>
|
|
@@ -789,6 +1249,120 @@ campaigns = MailerLite::Campaigns.new
|
|
|
789
1249
|
campaigns.languages()
|
|
790
1250
|
```
|
|
791
1251
|
|
|
1252
|
+
## E-commerce
|
|
1253
|
+
|
|
1254
|
+
<a name="e-commerce"></a>
|
|
1255
|
+
|
|
1256
|
+
### Shops
|
|
1257
|
+
|
|
1258
|
+
```ruby
|
|
1259
|
+
require "mailerlite-ruby"
|
|
1260
|
+
|
|
1261
|
+
shops = MailerLite::Ecommerce::Shops.new
|
|
1262
|
+
|
|
1263
|
+
shops.list(limit: 25)
|
|
1264
|
+
shops.get('shop_id')
|
|
1265
|
+
shops.create({ name: 'My shop', url: 'https://shop.example.com', currency: 'EUR' })
|
|
1266
|
+
shops.update(shop_id: 'shop_id', params: { name: 'New name' })
|
|
1267
|
+
shops.delete('shop_id')
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
### Products and variants
|
|
1271
|
+
|
|
1272
|
+
```ruby
|
|
1273
|
+
products = MailerLite::Ecommerce::Products.new
|
|
1274
|
+
|
|
1275
|
+
products.list(shop_id: 'shop_id', filter: { enabled: true }, sort: '-created_at')
|
|
1276
|
+
products.get(shop_id: 'shop_id', product_id: 'product_id')
|
|
1277
|
+
products.create(shop_id: 'shop_id', params: { name: 'Red T-shirt', price: 19.99 })
|
|
1278
|
+
products.update(shop_id: 'shop_id', product_id: 'product_id', params: { price: 24.99 })
|
|
1279
|
+
products.delete(shop_id: 'shop_id', product_id: 'product_id')
|
|
1280
|
+
products.change_status(shop_id: 'shop_id', product_id: 'product_id', enabled: false)
|
|
1281
|
+
products.assign_categories(shop_id: 'shop_id', product_id: 'product_id', category_ids: ['category_id'], replace: true)
|
|
1282
|
+
|
|
1283
|
+
variants = MailerLite::Ecommerce::ProductVariants.new
|
|
1284
|
+
|
|
1285
|
+
variants.list(shop_id: 'shop_id', product_id: 'product_id')
|
|
1286
|
+
variants.sync(shop_id: 'shop_id', product_id: 'product_id', variants: [{ name: 'Large', attributes: { size: 'L' }, resource_id: 'variant-l' }])
|
|
1287
|
+
variants.update(shop_id: 'shop_id', product_id: 'product_id', variant_id: 'variant_id', params: { name: 'Extra large', attributes: { size: 'XL' } })
|
|
1288
|
+
variants.delete(shop_id: 'shop_id', product_id: 'product_id', variant_id: 'variant_id')
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
### Categories
|
|
1292
|
+
|
|
1293
|
+
```ruby
|
|
1294
|
+
categories = MailerLite::Ecommerce::Categories.new
|
|
1295
|
+
|
|
1296
|
+
categories.list(shop_id: 'shop_id')
|
|
1297
|
+
categories.get(shop_id: 'shop_id', category_id: 'category_id')
|
|
1298
|
+
categories.create(shop_id: 'shop_id', params: { name: 'Hats' })
|
|
1299
|
+
categories.update(shop_id: 'shop_id', category_id: 'category_id', params: { name: 'Caps' })
|
|
1300
|
+
categories.delete(shop_id: 'shop_id', category_id: 'category_id')
|
|
1301
|
+
categories.products(shop_id: 'shop_id', category_id: 'category_id')
|
|
1302
|
+
categories.assign_product(shop_id: 'shop_id', category_id: 'category_id', product_id: 'product_id')
|
|
1303
|
+
categories.unassign_product(shop_id: 'shop_id', category_id: 'category_id', product_id: 'product_id')
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
### Customers, orders and carts
|
|
1307
|
+
|
|
1308
|
+
```ruby
|
|
1309
|
+
customers = MailerLite::Ecommerce::Customers.new
|
|
1310
|
+
customers.list(shop_id: 'shop_id', filter: { email: 'customer@example.com' })
|
|
1311
|
+
customers.create(shop_id: 'shop_id', params: { email: 'customer@example.com', create_subscriber: true })
|
|
1312
|
+
customers.update(shop_id: 'shop_id', customer_id: 'customer_id', params: { name: 'Jane' })
|
|
1313
|
+
customers.delete(shop_id: 'shop_id', customer_id: 'customer_id')
|
|
1314
|
+
|
|
1315
|
+
orders = MailerLite::Ecommerce::Orders.new
|
|
1316
|
+
orders.list(shop_id: 'shop_id', filter: { attributed: true, email_id: 'email_id' })
|
|
1317
|
+
orders.create(shop_id: 'shop_id', params: {
|
|
1318
|
+
customer: { email: 'customer@example.com' },
|
|
1319
|
+
cart: { items: [{ ecommerce_product_id: 'product_id', quantity: 1, price: 19.99 }] },
|
|
1320
|
+
status: 'complete'
|
|
1321
|
+
})
|
|
1322
|
+
orders.update(shop_id: 'shop_id', order_id: 'order_id', params: { status: 'complete' })
|
|
1323
|
+
orders.delete(shop_id: 'shop_id', order_id: 'order_id')
|
|
1324
|
+
|
|
1325
|
+
carts = MailerLite::Ecommerce::Carts.new
|
|
1326
|
+
carts.list(shop_id: 'shop_id')
|
|
1327
|
+
carts.update(shop_id: 'shop_id', cart_id: 'cart_id', params: { checkout_url: 'https://shop.example.com/cart' })
|
|
1328
|
+
|
|
1329
|
+
cart_items = MailerLite::Ecommerce::CartItems.new
|
|
1330
|
+
cart_items.list(shop_id: 'shop_id', cart_id: 'cart_id')
|
|
1331
|
+
cart_items.update(shop_id: 'shop_id', cart_id: 'cart_id', item_id: 'item_id', params: { quantity: 2 })
|
|
1332
|
+
cart_items.delete(shop_id: 'shop_id', cart_id: 'cart_id', item_id: 'item_id')
|
|
1333
|
+
```
|
|
1334
|
+
|
|
1335
|
+
### Imports
|
|
1336
|
+
|
|
1337
|
+
```ruby
|
|
1338
|
+
imports = MailerLite::Ecommerce::Imports.new
|
|
1339
|
+
|
|
1340
|
+
imports.products(shop_id: 'shop_id', products: [{ name: 'Red T-shirt', price: 19.99 }])
|
|
1341
|
+
imports.categories(shop_id: 'shop_id', categories: [{ name: 'Hats' }])
|
|
1342
|
+
imports.customers(shop_id: 'shop_id', customers: [{ email: 'customer@example.com' }])
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
### Revenue reports and settings
|
|
1346
|
+
|
|
1347
|
+
```ruby
|
|
1348
|
+
MailerLite::Ecommerce::Shops.new.stats(shop_id: 'shop_id', start_date: '2026-10-01', end_date: '2026-10-31')
|
|
1349
|
+
|
|
1350
|
+
campaigns = MailerLite::Campaigns.new
|
|
1351
|
+
campaigns.ecommerce_stats(campaign_id: 'campaign_id', shop_id: 'shop_id')
|
|
1352
|
+
campaigns.ecommerce_orders(campaign_id: 'campaign_id', shop_id: 'shop_id')
|
|
1353
|
+
|
|
1354
|
+
subscribers = MailerLite::Subscribers.new
|
|
1355
|
+
subscribers.ecommerce_stats(subscriber_id: 'subscriber_id', shop_id: 'shop_id')
|
|
1356
|
+
subscribers.ecommerce_orders(subscriber_id: 'subscriber_id', shop_id: 'shop_id')
|
|
1357
|
+
|
|
1358
|
+
automations = MailerLite::Automations.new
|
|
1359
|
+
automations.ecommerce_stats(automation_id: 'automation_id')
|
|
1360
|
+
automations.email_ecommerce_stats(automation_id: 'automation_id', email_id: 'email_id')
|
|
1361
|
+
automations.ecommerce_orders(automation_id: 'automation_id', time_frame: 'all_time')
|
|
1362
|
+
|
|
1363
|
+
MailerLite::Ecommerce::Settings.new.get
|
|
1364
|
+
```
|
|
1365
|
+
|
|
792
1366
|
# Testing
|
|
793
1367
|
|
|
794
1368
|
```bash
|