klaviyo 1.2.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4761ff7c9edac6dd8dec7efd826f0b9a903022ced70b8938d9db3adfdc9f16ac
4
- data.tar.gz: f9bca9ccb221bf7a30387a60e4fde3f6adba9e814702266fc0b869c5c470046b
3
+ metadata.gz: e41bce0307198c5fdf2ed370683115011973e35a53a79e106ce5fbf3b9ae3db1
4
+ data.tar.gz: c3a43df8eec9a79c7fa7b0e7c6d61f8bb715d3e3c0e62b855e3d822ea831a027
5
5
  SHA512:
6
- metadata.gz: 0da39baf09b301c7df78833d2a9d62bc8f72b2512c06b4c67ca247a863f72d4563512915037ad80aff05168cb41d3830dbec56b3e2bda3605d7a8f1b7826baf4
7
- data.tar.gz: d555098395599b4e1b9c725f815229949e0c208c00d0b387fcc00ac3071763d5aef830e3cf5316f71e7f84900e950bad27757370ab5a0b810f07a05e519541e0
6
+ metadata.gz: d562be7fd7515a89585448e2ecff320f39fe728a39b4124c248b8db4673dae68c1a3fee7f5189d4f1bfffff6b0b131d5975c6550bec03a2777790898064e0fe6
7
+ data.tar.gz: 8524d7358694da9ddddee84d0a2fe4fdaf532ecdd37502ab07fa8e328199c9309eaeeb1d6a177f76569d83c39df8770bc024ee905729be9986a5a7f8339fd4c8
data/klaviyo.gemspec CHANGED
@@ -1,18 +1,18 @@
1
- files = ['klaviyo.gemspec', '{lib}/**/*'].map {|f| Dir[f]}.flatten
1
+ files = ['klaviyo.gemspec', '{lib}/**/**/*'].map {|f| Dir[f]}.flatten
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'klaviyo'
5
- s.version = '1.2.0'
6
- s.date = '2020-09-28'
5
+ s.version = '2.4.0'
6
+ s.date = '2022-01-19'
7
7
  s.summary = 'You heard us, a Ruby wrapper for the Klaviyo API'
8
8
  s.description = 'Ruby wrapper for the Klaviyo API'
9
9
  s.authors = ['Klaviyo Team']
10
- s.email = 'hello@klaviyo.com'
10
+ s.email = 'libraries@klaviyo.com'
11
11
  s.files = files
12
12
  s.homepage = 'https://www.klaviyo.com/'
13
13
  s.require_path = 'lib'
14
- s.has_rdoc = false
15
14
  s.add_dependency 'json'
16
15
  s.add_dependency 'rack'
17
16
  s.add_dependency 'escape'
17
+ s.add_dependency 'faraday'
18
18
  end
@@ -0,0 +1,45 @@
1
+ module Klaviyo
2
+ class Campaigns < Client
3
+ CANCEL = 'cancel'
4
+ CAMPAIGN = 'campaign'
5
+ CAMPAIGNS = 'campaigns'
6
+ SEND = 'send'
7
+
8
+ # Retrieves all the campaigns from Klaviyo account
9
+ # @kwarg :api_key [String] private API key for this request
10
+ # @return [List] of JSON formatted campaing objects
11
+ def self.get_campaigns(api_key: nil)
12
+ v1_request(HTTP_GET, CAMPAIGNS, api_key: api_key)
13
+ end
14
+
15
+ # Retrieves the details of the list
16
+ # @param campaign_id the if of campaign
17
+ # @kwarg :api_key [String] private API key for this request
18
+ # @return [JSON] a JSON object containing information about the campaign
19
+ def self.get_campaign_details(campaign_id, api_key: nil)
20
+ path = "#{CAMPAIGN}/#{campaign_id}"
21
+
22
+ v1_request(HTTP_GET, path, api_key: api_key)
23
+ end
24
+
25
+ # Sends the campaign immediately
26
+ # @param campaign_id [String] the id of campaign
27
+ # @kwarg :api_key [String] private API key for this request
28
+ # @return will return with HTTP ok in case of success
29
+ def self.send_campaign(campaign_id, api_key: nil)
30
+ path = "#{CAMPAIGN}/#{campaign_id}/#{SEND}"
31
+
32
+ v1_request(HTTP_POST, path, api_key: api_key)
33
+ end
34
+
35
+ # Cancels the campaign with specified campaign_id
36
+ # @param campaign_id [String] the id of campaign
37
+ # @kwarg :api_key [String] private API key for this request
38
+ # @return [JSON] a JSON object containing the campaign details
39
+ def self.cancel_campaign(campaign_id, api_key: nil)
40
+ path = "#{CAMPAIGN}/#{campaign_id}/#{CANCEL}"
41
+
42
+ v1_request(HTTP_POST, path, api_key: api_key)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module Klaviyo
2
+ class DataPrivacy < Client
3
+ DATA_PRIVACY = 'data-privacy'
4
+ DELETION_REQUEST = 'deletion-request'
5
+
6
+ # Submits a data privacy-related deletion request
7
+ # @param id_type [String] 'email' or 'phone_number' or 'person_id
8
+ # @param identifier [String] value for the identifier specified
9
+ # @kwarg :api_key [String] private API key for this request
10
+ # @return a dictionary with a confirmation that deletion task submitted for the customer
11
+ def self.request_profile_deletion(id_type, identifier, api_key: nil)
12
+ unless ['email', 'phone_number', 'person_id'].include? id_type
13
+ raise Klaviyo::KlaviyoError.new(INVALID_ID_TYPE_ERROR)
14
+ end
15
+ data = Hash[id_type.to_sym, identifier]
16
+ path = "#{DATA_PRIVACY}/#{DELETION_REQUEST}"
17
+ v2_request(HTTP_POST, path, api_key: api_key, **data)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,104 @@
1
+ module Klaviyo
2
+ class EmailTemplates < Client
3
+ EMAIL_TEMPLATES = 'email-templates'
4
+ EMAIL_TEMPLATE = 'email-template'
5
+ CLONE = 'clone'
6
+ RENDER = 'render'
7
+ SEND = 'send'
8
+
9
+ # Returns a list of all the email templates you've created.
10
+ # The templates are returned in sorted order by name.
11
+ # @kwarg :api_key [String] private API key for this request
12
+ # @return [List] of JSON formatted email template objects
13
+ def self.get_templates(api_key: nil)
14
+ v1_request(HTTP_GET, EMAIL_TEMPLATES, api_key: api_key)
15
+ end
16
+
17
+ # Creates a new email template
18
+ # @param :name [String] The name of the email template
19
+ # @param :html [String] The HTML content for this template
20
+ # @kwarg :api_key [String] private API key for this request
21
+ # @return [JSON] a JSON object containing information about the email template
22
+ def self.create_template(name: nil, html: nil, api_key: nil)
23
+ params = {
24
+ name: name,
25
+ html: html
26
+ }
27
+ v1_request(HTTP_POST, EMAIL_TEMPLATES, api_key: api_key, content_type: CONTENT_URL_FORM, params: params)
28
+ end
29
+
30
+ # Updates the name and/or HTML content of a template. Only updates imported
31
+ # HTML templates; does not currently update drag & drop templates
32
+ # @param template_id [String] The id of the email template
33
+ # @param :name [String] The name of the email template
34
+ # @param :html [String] The HTML content for this template
35
+ # @kwarg :api_key [String] private API key for this request
36
+ # @return [JSON] a JSON object containing information about the email template
37
+ def self.update_template(template_id, name:, html:, api_key: nil)
38
+ path = "#{EMAIL_TEMPLATE}/#{template_id}"
39
+ params = {
40
+ name: name,
41
+ html: html
42
+ }
43
+ v1_request(HTTP_PUT, path, api_key: api_key, **params)
44
+ end
45
+
46
+ # Deletes a given template.
47
+ # @param template_id [String] The id of the email template
48
+ # @kwarg :api_key [String] private API key for this request
49
+ # @return [JSON] a JSON object containing information about the email template
50
+ def self.delete_template(template_id, api_key: nil)
51
+ path = "#{EMAIL_TEMPLATE}/#{template_id}"
52
+ v1_request(HTTP_DELETE, path, api_key: api_key)
53
+ end
54
+
55
+ # Creates a copy of a given template with a new name
56
+ # @param template_id [String] The id of the email template to copy
57
+ # @param :name [String] The name of the newly cloned email template
58
+ # @kwarg :api_key [String] private API key for this request
59
+ # @return [JSON] a JSON object containing information about the email template
60
+ def self.clone_template(template_id, name:, api_key: nil)
61
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{CLONE}"
62
+ params = {
63
+ name: name
64
+ }
65
+ v1_request(HTTP_POST, path, api_key: api_key, content_type: CONTENT_URL_FORM, params: params)
66
+ end
67
+
68
+ # Renders the specified template with the provided data and return HTML
69
+ # and text versions of the email
70
+ # @param template_id [String] The id of the email template to copy
71
+ # @param :context [Hash] The context the email template will be rendered with
72
+ # @kwarg :api_key [String] private API key for this request
73
+ # @return [JSON] a JSON object containing information about the email template
74
+ def self.render_template(template_id, context: {}, api_key: nil)
75
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{RENDER}"
76
+ params = {
77
+ context: context
78
+ }
79
+ v1_request(HTTP_POST, path, api_key: api_key, content_type: CONTENT_URL_FORM, params: params)
80
+ end
81
+
82
+ # Renders the specified template with the provided data and then send the
83
+ # contents in an email via the service specified
84
+ # @param template_id [String] The id of the email template to copy
85
+ # @param :from_email [String] The from email address; used in the reply-to header
86
+ # @param :from_name [String] The name the email is sent from
87
+ # @param :subject [String] The subject of the email template
88
+ # @param :to [Mixed] The email this template is being sent to
89
+ # @param :context [Hash] The context the email template will be rendered with
90
+ # @kwarg :api_key [String] private API key for this request
91
+ # @return [JSON] a JSON object containing information about the email template
92
+ def self.send_template(template_id, from_email:, from_name:, subject:, to:, context: {}, api_key: nil)
93
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{SEND}"
94
+ params = {
95
+ from_email: from_email,
96
+ from_name: from_name,
97
+ subject: subject,
98
+ to: to,
99
+ context: context
100
+ }
101
+ v1_request(HTTP_POST, path, api_key: api_key, content_type: CONTENT_URL_FORM, params: params)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,182 @@
1
+ module Klaviyo
2
+ class Lists < Client
3
+ EXCLUSIONS = 'exclusions'
4
+ GROUP = 'group'
5
+ LIST = 'list'
6
+ LISTS = 'lists'
7
+ MEMBERS = 'members'
8
+ SUBSCRIBE = 'subscribe'
9
+
10
+ # Creates a new list
11
+ # @param list_name [String] the list name
12
+ # @kwarg :api_key [String] private API key for this request
13
+ # @return will return with HTTP OK on success
14
+ def self.create_list(list_name, api_key: nil)
15
+ body = {
16
+ :list_name => list_name
17
+ }
18
+ v2_request(HTTP_POST, LISTS, api_key: api_key, **body)
19
+ end
20
+
21
+ # Retrieves all the lists in the Klaviyo account
22
+ # @kwarg :api_key [String] private API key for this request
23
+ # @return [List] a list of JSON objects of the name and id for each list
24
+ def self.get_lists(api_key: nil)
25
+ v2_request(HTTP_GET, LISTS, api_key: api_key)
26
+ end
27
+
28
+ # Retrieves the details of the list
29
+ # @param list_id [String] the id of the list
30
+ # @kwarg :api_key [String] private API key for this request
31
+ # @return [JSON] a JSON object containing information about the list
32
+ def self.get_list_details(list_id, api_key: nil)
33
+ path = "#{LIST}/#{list_id}"
34
+ v2_request(HTTP_GET, path, api_key: api_key)
35
+ end
36
+
37
+ # Updates the properties of a list
38
+ # @param list_id [String] the id of the list
39
+ # @param list_name [String] the new name of the list
40
+ # @kwarg :api_key [String] private API key for this request
41
+ # @return will return with HTTP OK on success
42
+ def self.update_list_details(list_id, list_name, api_key: nil)
43
+ path = "#{LIST}/#{list_id}"
44
+ body = {
45
+ :list_name => list_name
46
+ }
47
+ v2_request(HTTP_PUT, path, api_key: api_key, **body)
48
+ end
49
+
50
+ # Deletes a list
51
+ # @param list_id [String] the id of the list
52
+ # @kwarg :api_key [String] private API key for this request
53
+ # @return will return with HTTP OK on success
54
+ def self.delete_list(list_id, api_key: nil)
55
+ path = "#{LIST}/#{list_id}"
56
+ v2_request(HTTP_DELETE, path, api_key: api_key)
57
+ end
58
+
59
+ # Check if profiles are in a list and not supressed
60
+ # @param list_id [String] the id of the list
61
+ # @param :emails [List] the emails of the profiles to check
62
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
63
+ # @param :push_tokens [List] push tokens of the profiles to check
64
+ # @kwarg :api_key [String] private API key for this request
65
+ # @return A list of JSON objects of the profiles. Profiles that are
66
+ # supressed or not found are not included.
67
+ def self.check_list_subscriptions(list_id, api_key: nil, emails: [], phone_numbers: [], push_tokens: [])
68
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
69
+ params = {
70
+ :emails => emails,
71
+ :phone_numbers => phone_numbers,
72
+ :push_tokens => push_tokens
73
+ }
74
+ v2_request(HTTP_GET, path, api_key: api_key, **params)
75
+ end
76
+
77
+ # Subscribe profiles to a list.
78
+ # @param list_id [String] the id of the list
79
+ # @param profiles [List] a list of JSON objects. Each object requires either
80
+ # an email or phone number key.
81
+ # @kwarg :api_key [String] private API key for this request
82
+ # @return will retun HTTP OK on success. If the list is single opt-in then a
83
+ # list of records containing the email address, phone number, push token,
84
+ # and the corresponding profile ID will also be included.
85
+ def self.add_subscribers_to_list(list_id, api_key: nil, profiles: [])
86
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
87
+ params = {
88
+ :profiles => profiles
89
+ }
90
+ v2_request(HTTP_POST, path, api_key: api_key, **params)
91
+ end
92
+
93
+ # Unsubscribe and remove profiles from a list
94
+ # @param list_id [String] the id of the list
95
+ # @param :emails [List] the emails of the profiles to check
96
+ # @kwarg :api_key [String] private API key for this request
97
+ # @return will return with HTTP OK on success
98
+ def self.unsubscribe_from_list(list_id, api_key: nil, emails: [])
99
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
100
+ params = {
101
+ :emails => emails
102
+ }
103
+ v2_request(HTTP_DELETE, path, api_key: api_key, **params)
104
+ end
105
+
106
+ # Add profiles to a list
107
+ # @param list_id [String] the id of the list
108
+ # @param :profiles [List] A list of JSON objects. Each object is a profile
109
+ # that will be added to the list
110
+ # @kwarg :api_key [String] private API key for this request
111
+ # @return will return with HTTP OK on success and a list of records of the
112
+ # corresponding profile id
113
+ def self.add_to_list(list_id, api_key: nil, profiles: [])
114
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
115
+ params = {
116
+ :profiles => profiles
117
+ }
118
+ v2_request(HTTP_POST, path, api_key: api_key, **params)
119
+ end
120
+
121
+ # Check if profiles are on a list
122
+ # @param list_id [String] the id of the list
123
+ # @param :emails [List] the emails of the profiles to check
124
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
125
+ # @param :push_tokens [List] push tokens of the profiles to check
126
+ # @kwarg :api_key [String] private API key for this request
127
+ # @return A list of JSON objects of the profiles. Profiles that are
128
+ # supressed or not found are not included.
129
+ def self.check_list_memberships(list_id, api_key: nil, emails: [], phone_numbers: [], push_tokens: [])
130
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
131
+ params = {
132
+ :emails => emails,
133
+ :phone_numbers => phone_numbers,
134
+ :push_tokens => push_tokens
135
+ }
136
+ v2_request(HTTP_GET, path, api_key: api_key, **params)
137
+ end
138
+
139
+ # Remove profiles from a list
140
+ # @param list_id [String] the id of the list
141
+ # @param :emails [List] the emails of the profiles to check
142
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
143
+ # @param :push_tokens [List] push tokens of the profiles to check
144
+ # @kwarg :api_key [String] private API key for this request
145
+ # @return will return with HTTP OK on success
146
+ def self.remove_from_list(list_id, api_key: nil, emails: [], phone_numbers: [], push_tokens: [])
147
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
148
+ params = {
149
+ :emails => emails,
150
+ :phone_numbers => phone_numbers,
151
+ :push_tokens => push_tokens
152
+ }
153
+ v2_request(HTTP_DELETE, path, api_key: api_key, **params)
154
+ end
155
+
156
+ # Get all emails, phone numbers, along with reasons for list exclusion
157
+ # @param list_id [String] the id of the list
158
+ # @param marker [Integer] a marker from a previous call to get the next batch
159
+ # @kwarg :api_key [String] private API key for this request
160
+ # @return [List] A list of JSON object for each profile with the reason for exclusion
161
+ def self.get_list_exclusions(list_id, api_key: nil, marker: nil)
162
+ path = "#{LIST}/#{list_id}/#{EXCLUSIONS}/#{ALL}"
163
+ params = {
164
+ :marker => marker
165
+ }
166
+ v2_request(HTTP_GET, path, api_key: api_key, **params)
167
+ end
168
+
169
+ # Get all of the emails, phone numbers, and push tokens for profiles in a given list or segment
170
+ # @param list_id [String] the id of the list
171
+ # @param marker [Integer] a marker from a previous call to get the next batch
172
+ # @kwarg :api_key [String] private API key for this request
173
+ # @return [List] A list of JSON objects for each profile with the id, email, phone number, and push token
174
+ def self.get_group_members(list_id, api_key: nil, marker: nil)
175
+ path = "#{GROUP}/#{list_id}/#{MEMBERS}/#{ALL}"
176
+ params = {
177
+ marker: marker
178
+ }
179
+ v2_request(HTTP_GET, path, api_key: api_key, **params)
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,85 @@
1
+ module Klaviyo
2
+ class Metrics < Client
3
+ EXPORT = 'export'
4
+
5
+ # Returns a list of all metrics in Klaviyo
6
+ # @param page [Integer] which page to return, default 0
7
+ # @param count [Integer] number of results to return, default 100
8
+ # @kwarg :api_key [String] private API key for this request
9
+ # @return a dictionary with a data property that contains an array of all the metrics
10
+ def self.get_metrics(page: DEFAULT_PAGE, count: DEFAULT_COUNT, api_key: nil)
11
+ params = {
12
+ :page => page,
13
+ :count => count
14
+ }
15
+ v1_request(HTTP_GET, METRICS, api_key: api_key, **params)
16
+ end
17
+
18
+ # Returns a batched timeline of all events in your Klaviyo account.
19
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
20
+ # @param count [Integer] number of results to return, default 100
21
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
22
+ # @kwarg :api_key [String] private API key for this request
23
+ # @return a dictionary with a data property that contains an array of the metrics
24
+ def self.get_metrics_timeline(since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC, api_key: nil)
25
+ path = "#{METRICS}/#{TIMELINE}"
26
+ params = {
27
+ :since => since,
28
+ :count => count,
29
+ :sort => sort
30
+ }
31
+ v1_request(HTTP_GET, path, api_key: api_key, **params)
32
+ end
33
+
34
+ # Returns a batched timeline for one specific type of metric.
35
+ # @param metric_id [String] the id of the metric
36
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
37
+ # @param count [Integer] number of results to return, default 100
38
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
39
+ # @kwarg :api_key [String] private API key for this request
40
+ # @return a dictionary with a data property that contains information about what metric the event tracks
41
+ def self.get_metric_timeline(metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC, api_key: nil)
42
+ path = "#{METRIC}/#{metric_id}/#{TIMELINE}"
43
+ params = {
44
+ :since => since,
45
+ :count => count,
46
+ :sort => sort
47
+ }
48
+ v1_request(HTTP_GET, path, api_key: api_key, **params)
49
+ end
50
+
51
+ # Export event data, optionally filtering and segmented on available event properties
52
+ # @param metric_id [String] the id of the metric
53
+ # @param start_date [String] Beginning of the timeframe to pull event data for. Default is 1 month ago
54
+ # @param end_date [String] End of the timeframe to pull event data for. Default is the current day
55
+ # @param unit [String] Granularity to bucket data points into - one of ‘day’, ‘week’, or ‘month’. Defaults to ‘day’.
56
+ # @param measurement [String or JSON-encoded list] Type of metric to fetch
57
+ # @param where [JSON-encoded list] Conditions to use to filter the set of events. A max of 1 condition can be given.
58
+ # @param by [String] The name of a property to segment the event data on. Where and by parameters cannot be specified at the same time.
59
+ # @param count [Integer] Maximum number of segments to return. The default value is 25.
60
+ # @kwarg :api_key [String] private API key for this request
61
+ # @return A dictionary relecting the input request parameters as well as a results property
62
+ def self.get_metric_export(metric_id,
63
+ start_date: nil,
64
+ end_date: nil,
65
+ unit: nil,
66
+ measurement: nil,
67
+ where: nil,
68
+ by: nil,
69
+ count: nil,
70
+ api_key: nil
71
+ )
72
+ path = "#{METRIC}/#{metric_id}/#{EXPORT}"
73
+ params = {
74
+ :start_date => start_date,
75
+ :end_date => end_date,
76
+ :unit => unit,
77
+ :measurement => measurement,
78
+ :where => where,
79
+ :by => by,
80
+ :count => count
81
+ }
82
+ v1_request(HTTP_GET, path, api_key: api_key, **params)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,72 @@
1
+ module Klaviyo
2
+ class Profiles < Client
3
+ PERSON = 'person'
4
+ PEOPLE = 'people'
5
+ SEARCH = 'search'
6
+
7
+ # Retrieves the id of the profile given email
8
+ # @param email [String] the email of the profile
9
+ # @kwarg :api_key [String] private API key for this request
10
+ # @return [JSON] a JSON object containing id of the profile
11
+ def self.get_profile_id_by_email(email, api_key: nil)
12
+ path = "#{PEOPLE}/#{SEARCH}"
13
+ params = {
14
+ :email => email
15
+ }
16
+ v2_request(HTTP_GET, path, api_key: api_key, **params)
17
+ end
18
+
19
+ # Retrieve all the data attributes for a Klaviyo Person ID.
20
+ # @param person_id [String] the id of the profile
21
+ # @kwarg :api_key [String] private API key for this request
22
+ # @return returns a person object
23
+ def self.get_person_attributes(person_id, api_key: nil)
24
+ path = "#{PERSON}/#{person_id}"
25
+ v1_request(HTTP_GET, path, api_key: api_key)
26
+ end
27
+
28
+ # Add or update one more more attributes for a Person
29
+ # @param person_id [String] the id of the profile
30
+ # @param kwargs [Key/value pairs] attributes to add/update in the profile
31
+ # @return returns the updated person object
32
+ def self.update_person_attributes(person_id, kwargs = {})
33
+ path = "#{PERSON}/#{person_id}"
34
+ v1_request(HTTP_PUT, path, **kwargs)
35
+ end
36
+
37
+ # Listing a person's event timeline
38
+ # @param person_id [String] the id of the profile
39
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
40
+ # @param count [Integer] number of results to return, default 100
41
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
42
+ # @kwarg :api_key [String] private API key for this request
43
+ # @return returns a dictionary containing a list of metric event objects
44
+ def self.get_person_metrics_timeline(person_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC, api_key: nil)
45
+ path = "#{PERSON}/#{person_id}/#{METRICS}/#{TIMELINE}"
46
+ params = {
47
+ :since => since,
48
+ :count => count,
49
+ :sort => sort
50
+ }
51
+ v1_request(HTTP_GET, path, api_key: api_key, **params)
52
+ end
53
+
54
+ # Listing a person's event timeline for a particular metric
55
+ # @param person_id [String] the id of the profile
56
+ # @param metric_id [String] the id of the metric
57
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
58
+ # @param count [Integer] number of results to return, default 100
59
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
60
+ # @kwarg :api_key [String] private API key for this request
61
+ # @return returns a dictionary containing a list of metric event objects
62
+ def self.get_person_metric_timeline(person_id, metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC, api_key: nil)
63
+ path = "#{PERSON}/#{person_id}/#{METRIC}/#{metric_id}/#{TIMELINE}"
64
+ params = {
65
+ :since => since,
66
+ :count => count,
67
+ :sort => sort
68
+ }
69
+ v1_request(HTTP_GET, path, api_key: api_key, **params)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,92 @@
1
+ module Klaviyo
2
+ class Public < Client
3
+ # Used for identifying customers and managing profile properties
4
+ #
5
+ # @kwarg :id [String] the customer or profile id
6
+ # @kwarg :email [String] the customer or profile email
7
+ # @kwarg :phone_number [String] the customer or profile phone number
8
+ # @kwarg :properties [Hash] properties of the profile to add or update
9
+ # @kwarg :token [String] public API token for this request
10
+ # @kwargs :method [String] the HTTP method to use for the request. Accepts 'get' or 'post'. Defaults to 'get'.
11
+ def self.identify(kwargs = {})
12
+ defaults = {:id => nil,
13
+ :email => nil,
14
+ :phone_number => nil,
15
+ :properties => {},
16
+ :method => HTTP_GET,
17
+ :token => nil
18
+ }
19
+ kwargs = defaults.merge(kwargs)
20
+
21
+ unless check_required_args(kwargs)
22
+ return
23
+ end
24
+
25
+ properties = kwargs[:properties]
26
+ properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
27
+ properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
28
+ properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
29
+
30
+ token = kwargs[:token] || Klaviyo.public_api_key || nil
31
+
32
+ params = {
33
+ :token => token,
34
+ :properties => properties
35
+ }
36
+
37
+ public_request(kwargs[:method], 'identify', **params)
38
+ end
39
+
40
+ # Used for tracking events and customer behaviors
41
+ #
42
+ # @param event [String] the event to track
43
+ # @kwarg :id [String] the customer or profile id
44
+ # @kwarg :email [String] the customer or profile email
45
+ # @kwarg :phone_number [String] the customer or profile phone number
46
+ # @kwarg :properties [Hash] properties of the event
47
+ # @kwargs :customer_properties [Hash] properties of the customer or profile
48
+ # @kwargs :time [Integer] timestamp of the event
49
+ # @kwarg :token [String] public API token for this request
50
+ # @kwargs :method [String] the HTTP method to use for the request. Accepts 'get' or 'post'. Defaults to 'get'.
51
+ def self.track(event, kwargs = {})
52
+ defaults = {
53
+ :id => nil,
54
+ :email => nil,
55
+ :phone_number => nil,
56
+ :properties => {},
57
+ :customer_properties => {},
58
+ :time => nil,
59
+ :method => HTTP_GET,
60
+ :token => nil
61
+ }
62
+
63
+ kwargs = defaults.merge(kwargs)
64
+
65
+ unless check_required_args(kwargs)
66
+ return
67
+ end
68
+
69
+ customer_properties = kwargs[:customer_properties]
70
+ customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
71
+ customer_properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
72
+ customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
73
+
74
+ token = kwargs[:token] || Klaviyo.public_api_key || nil
75
+
76
+ params = {
77
+ :token => token,
78
+ :event => event,
79
+ :properties => kwargs[:properties],
80
+ :customer_properties => customer_properties
81
+ }
82
+ params[:time] = kwargs[:time] if kwargs[:time]
83
+
84
+ public_request(kwargs[:method], 'track', **params)
85
+ end
86
+
87
+ def self.track_once(event, kwargs = {})
88
+ kwargs.update('__track_once__' => true)
89
+ track(event, kwargs)
90
+ end
91
+ end
92
+ end
@@ -1,77 +1,138 @@
1
- require 'open-uri'
2
- require 'base64'
3
- require 'json'
4
-
5
1
  module Klaviyo
6
- class KlaviyoError < StandardError; end
7
-
8
2
  class Client
9
- VERSION = '1.2.0'
10
- KL_USER_AGENT = "Ruby_Klaviyo/#{VERSION}"
3
+ BASE_API_URL = 'https://a.klaviyo.com/api'
4
+ V1_API = 'v1'
5
+ V2_API = 'v2'
11
6
 
12
- def initialize(api_key, url = 'https://a.klaviyo.com/')
13
- @api_key = api_key
14
- @url = url
15
- end
7
+ KL_VERSION = '2.4.0'
8
+ KL_USER_AGENT = "Ruby_Klaviyo/#{KL_VERSION}"
16
9
 
17
- def track(event, kwargs = {})
18
- defaults = {:id => nil, :email => nil, :properties => {}, :customer_properties => {}, :time => nil}
19
- kwargs = defaults.merge(kwargs)
10
+ HTTP_DELETE = 'delete'
11
+ HTTP_GET = 'get'
12
+ HTTP_POST = 'post'
13
+ HTTP_PUT = 'put'
20
14
 
21
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
22
- raise KlaviyoError.new('You must identify a user by email or ID')
23
- end
15
+ ALL = 'all'
16
+ METRIC = 'metric'
17
+ METRICS = 'metrics'
18
+ TIMELINE = 'timeline'
24
19
 
25
- customer_properties = kwargs[:customer_properties]
26
- customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
27
- customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
20
+ DEFAULT_COUNT = 100
21
+ DEFAULT_PAGE = 0
22
+ DEFAULT_SORT_DESC = 'desc'
28
23
 
29
- params = {
30
- :token => @api_key,
31
- :event => event,
32
- :properties => kwargs[:properties],
33
- :customer_properties => customer_properties,
34
- :ip => ''
35
- }
36
- params[:time] = kwargs[:time].to_time.to_i if kwargs[:time]
24
+ CONTENT_JSON = 'application/json'
25
+ CONTENT_URL_FORM = 'application/x-www-form-urlencoded'
37
26
 
38
- params = build_params(params)
39
- request('api/track', params)
40
- end
27
+ private
41
28
 
42
- def track_once(event, opts = {})
43
- opts.update('__track_once__' => true)
44
- track(event, opts)
29
+ def self.request(method, path, content_type, **kwargs)
30
+ check_private_api_key_exists(kwargs)
31
+ url = "#{BASE_API_URL}/#{path}"
32
+ connection = Faraday.new(
33
+ url: url,
34
+ headers: {
35
+ 'Content-Type' => content_type,
36
+ 'User-Agent' => KL_USER_AGENT
37
+ })
38
+ if content_type == CONTENT_JSON
39
+ kwargs[:body] = kwargs[:body].to_json
40
+ end
41
+ response = connection.send(method) do |req|
42
+ req.body = kwargs[:body] || nil
43
+ end
45
44
  end
46
45
 
47
- def identify(kwargs = {})
48
- defaults = {:id => nil, :email => nil, :properties => {}}
49
- kwargs = defaults.merge(kwargs)
46
+ def self.public_request(method, path, **kwargs)
47
+ check_public_api_key_is_valid(kwargs[:token])
48
+ if method == HTTP_GET
49
+ params = build_params(kwargs)
50
+ url = "#{BASE_API_URL}/#{path}?#{params}"
51
+ res = Faraday.get(url, {}, { 'User-Agent' => KL_USER_AGENT }).body
52
+ elsif method == HTTP_POST
53
+ url = URI("#{BASE_API_URL}/#{path}")
54
+ response = Faraday.post(url) do |req|
55
+ req.headers['Content-Type'] = CONTENT_URL_FORM
56
+ req.headers['Accept'] = 'text/html'
57
+ req.headers['User-Agent'] = KL_USER_AGENT
58
+ req.body = {data: "#{kwargs.to_json}"}
59
+ end
60
+ else
61
+ raise KlaviyoError.new(INVALID_HTTP_METHOD)
62
+ end
63
+ end
50
64
 
51
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
52
- raise KlaviyoError.new('You must identify a user by email or ID')
65
+ def self.v1_request(method, path, content_type: CONTENT_JSON, **kwargs)
66
+ if content_type == CONTENT_URL_FORM
67
+ priv_api_key = kwargs[:api_key] || Klaviyo.private_api_key || nil
68
+ data = {
69
+ :body => {
70
+ :api_key => priv_api_key
71
+ }
72
+ }
73
+ data[:body] = data[:body].merge(kwargs[:params])
74
+ full_url = "#{V1_API}/#{path}"
75
+ request(method, full_url, content_type, **data)
76
+ else
77
+ defaults = {:page => nil,
78
+ :count => nil,
79
+ :since => nil,
80
+ :sort => nil}
81
+ params = defaults.merge(kwargs)
82
+ query_params = encode_params(params)
83
+ priv_api_key = kwargs[:api_key] || Klaviyo.private_api_key || nil
84
+ full_url = "#{V1_API}/#{path}?api_key=#{priv_api_key}#{query_params}"
85
+ request(method, full_url, content_type, body: {api_key: priv_api_key})
53
86
  end
87
+ end
54
88
 
55
- properties = kwargs[:properties]
56
- properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
57
- properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
89
+ def self.v2_request(method, path, **kwargs)
90
+ path = "#{V2_API}/#{path}"
91
+ priv_api_key = kwargs[:api_key] || Klaviyo.private_api_key || nil
92
+ key = {
93
+ :api_key => "#{priv_api_key}"
94
+ }
95
+ data = {}
96
+ data[:body] = kwargs.merge(key)
97
+ request(method, path, CONTENT_JSON, **data)
98
+ end
58
99
 
59
- params = build_params({
60
- :token => @api_key,
61
- :properties => properties
62
- })
63
- request('api/identify', params)
100
+ def self.build_params(params)
101
+ "data=#{CGI.escape(Base64.encode64(JSON.generate(params)).gsub(/\n/, ''))}"
64
102
  end
65
103
 
66
- private
104
+ def self.check_required_args(kwargs)
105
+ if kwargs[:email].to_s.empty? and kwargs[:phone_number].to_s.empty? and kwargs[:id].to_s.empty?
106
+ raise Klaviyo::KlaviyoError.new(REQUIRED_ARG_ERROR)
107
+ else
108
+ return true
109
+ end
110
+ end
67
111
 
68
- def build_params(params)
69
- "data=#{CGI.escape Base64.encode64(JSON.generate(params)).gsub(/\n/,'')}"
112
+ def self.check_private_api_key_exists(kwargs)
113
+ if !Klaviyo.private_api_key && kwargs[:body][:api_key].nil?
114
+ raise KlaviyoError.new(NO_PRIVATE_API_KEY_ERROR)
115
+ end
70
116
  end
71
117
 
72
- def request(path, params)
73
- url = "#{@url}#{path}?#{params}"
74
- open(url, 'User-Agent' => KL_USER_AGENT).read == '1'
118
+ def self.check_public_api_key_is_valid(token)
119
+ if !token
120
+ raise KlaviyoError.new(NO_PUBLIC_API_KEY_ERROR)
121
+ end
122
+ if ( token =~ /pk_\w{34}$/ ) == 0
123
+ warn(PRIVATE_KEY_AS_PUBLIC)
124
+ elsif ( token =~ /\w{6}$/ ) != 0
125
+ raise KlaviyoError.new(INCORRECT_PUBLIC_API_KEY_LENGTH)
126
+ end
127
+ end
128
+
129
+ def self.encode_params(kwargs)
130
+ kwargs.select!{|k, v| v}
131
+ params = URI.encode_www_form(kwargs)
132
+
133
+ if !params.empty?
134
+ return "&#{params}"
135
+ end
75
136
  end
76
137
  end
77
138
  end
@@ -0,0 +1,30 @@
1
+ require 'open-uri'
2
+ require 'base64'
3
+ require 'json'
4
+ require 'faraday'
5
+
6
+ require_relative './client'
7
+ require_relative 'apis/public'
8
+ require_relative 'apis/lists'
9
+ require_relative 'apis/metrics'
10
+ require_relative 'apis/profiles'
11
+ require_relative 'apis/campaigns'
12
+ require_relative 'apis/email_templates'
13
+ require_relative 'apis/data_privacy'
14
+
15
+ module Klaviyo
16
+ class << self
17
+ attr_accessor :public_api_key
18
+ attr_accessor :private_api_key
19
+ end
20
+
21
+ class KlaviyoError < StandardError; end
22
+
23
+ NO_PRIVATE_API_KEY_ERROR = 'Please provide your Private API key for this request'
24
+ NO_PUBLIC_API_KEY_ERROR = 'Please provide your Public API key for this request'
25
+ REQUIRED_ARG_ERROR = 'You must identify a user by email, ID or phone_number'
26
+ INVALID_ID_TYPE_ERROR = 'Invalid id_type provided, must be one of: email, phone_number, person_id'
27
+ PRIVATE_KEY_AS_PUBLIC = 'Private API key added in place of Public API key'
28
+ INCORRECT_PUBLIC_API_KEY_LENGTH = 'Public API Key must be 6 characters'
29
+ INVALID_HTTP_METHOD = 'Invalid HTTP method present, please use "get" or "post"'
30
+ end
data/lib/klaviyo.rb CHANGED
@@ -1 +1 @@
1
- require 'klaviyo/client'
1
+ require 'klaviyo/klaviyo_module'
data/lib/rack/klaviyo.rb CHANGED
@@ -55,6 +55,7 @@ module Rack
55
55
  <script text="text/javascript">
56
56
  var _learnq = _learnq || [];
57
57
  _learnq.push(['account', '#{@api_key}']);
58
+
58
59
  (function () {
59
60
  var b = document.createElement('script'); b.type = 'text/javascript'; b.async = true;
60
61
  b.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'a.klaviyo.com/media/js/analytics/analytics.js';
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klaviyo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Klaviyo Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-28 00:00:00.000000000 Z
11
+ date: 2022-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -52,15 +52,37 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faraday
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Ruby wrapper for the Klaviyo API
56
- email: hello@klaviyo.com
70
+ email: libraries@klaviyo.com
57
71
  executables: []
58
72
  extensions: []
59
73
  extra_rdoc_files: []
60
74
  files:
61
75
  - klaviyo.gemspec
62
76
  - lib/klaviyo.rb
77
+ - lib/klaviyo/apis/campaigns.rb
78
+ - lib/klaviyo/apis/data_privacy.rb
79
+ - lib/klaviyo/apis/email_templates.rb
80
+ - lib/klaviyo/apis/lists.rb
81
+ - lib/klaviyo/apis/metrics.rb
82
+ - lib/klaviyo/apis/profiles.rb
83
+ - lib/klaviyo/apis/public.rb
63
84
  - lib/klaviyo/client.rb
85
+ - lib/klaviyo/klaviyo_module.rb
64
86
  - lib/rack/klaviyo.rb
65
87
  homepage: https://www.klaviyo.com/
66
88
  licenses: []