klaviyo 1.0.0 → 2.0.9

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
- SHA1:
3
- metadata.gz: b500c9a9b23a831e8dbd4973b10e86420af64d70
4
- data.tar.gz: 75585569e42545281d0622a40c5f888f261d6622
2
+ SHA256:
3
+ metadata.gz: f20097f9b9538503cc8f541dd7e6d71c6c70904e51fdd59f636670f56d0b53c5
4
+ data.tar.gz: 98032c0e8a4ac60b16501495b71d35ce09bd28bd62fce4c49392448929555ffa
5
5
  SHA512:
6
- metadata.gz: eecb6c11c4b4a893271f914db129724362ae6d74d5950ef79b5aa90e83939ea6c937af40122768b2e1f409640cef72587e19bfc3af05b1fda9dc33c4b46c3c20
7
- data.tar.gz: 98d0566c1c134ea9ab32c0968927019d0231532aeeb72a86e432aeef60a4314f54dd12450269d9dc0762a373feef0b15dfdba8a68b2ef387fe8ce29c9576ff39
6
+ metadata.gz: e4f99398385906828f37a4e1f25f05ca76493a905d526177da2cc189301fba84adc76551711213c85003337b0278d0cade9c8ba52e0c0726176465fd2c8132cd
7
+ data.tar.gz: e109724a853cbf44a3546298fdfc04037a9cfb748b72a3edd96fab1475e209a3ea67c697ce940ff54d6aac57120f37aa853076398c016995b1b4b11f70279694
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.0.0'
6
- s.date = '2014-09-06'
5
+ s.version = '2.0.9'
6
+ s.date = '2021-07-30'
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'
18
- end
17
+ s.add_dependency 'faraday'
18
+ end
@@ -0,0 +1,41 @@
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
+ # @return [List] of JSON formatted campaing objects
10
+ def self.get_campaigns()
11
+ v1_request(HTTP_GET, CAMPAIGNS)
12
+ end
13
+
14
+ # Retrieves the details of the list
15
+ # @param campaign_id the if of campaign
16
+ # @return [JSON] a JSON object containing information about the campaign
17
+ def self.get_campaign_details(campaign_id)
18
+ path = "#{CAMPAIGN}/#{campaign_id}"
19
+
20
+ v1_request(HTTP_GET, path)
21
+ end
22
+
23
+ # Sends the campaign immediately
24
+ # @param campaign_id [String] the id of campaign
25
+ # @return will return with HTTP ok in case of success
26
+ def self.send_campaign(campaign_id)
27
+ path = "#{CAMPAIGN}/#{campaign_id}/#{SEND}"
28
+
29
+ v1_request(HTTP_POST, path)
30
+ end
31
+
32
+ # Cancels the campaign with specified campaign_id
33
+ # @param campaign_id [String] the id of campaign
34
+ # @return [JSON] a JSON object containing the campaign details
35
+ def self.cancel_campaign(campaign_id)
36
+ path = "#{CAMPAIGN}/#{campaign_id}/#{CANCEL}"
37
+
38
+ v1_request(HTTP_POST, path)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
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
+ # @return a dictionary with a confirmation that deletion task submitted for the customer
10
+ def self.request_profile_deletion(id_type, identifier)
11
+ unless ['email', 'phone_number', 'person_id'].include? id_type
12
+ raise Klaviyo::KlaviyoError.new(INVALID_ID_TYPE_ERROR)
13
+ end
14
+ data = Hash[id_type.to_sym, identifier]
15
+ path = "#{DATA_PRIVACY}/#{DELETION_REQUEST}"
16
+ v2_request(HTTP_POST, path, **data)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,97 @@
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
+ # @return [List] of JSON formatted email template objects
12
+ def self.get_templates()
13
+ v1_request(HTTP_GET, EMAIL_TEMPLATES)
14
+ end
15
+
16
+ # Creates a new email template
17
+ # @param :name [String] The name of the email template
18
+ # @param :html [String] The HTML content for this template
19
+ # @return [JSON] a JSON object containing information about the email template
20
+ def self.create_template(name: nil, html: nil)
21
+ params = {
22
+ name: name,
23
+ html: html
24
+ }
25
+ v1_request(HTTP_POST, EMAIL_TEMPLATES, content_type: CONTENT_URL_FORM, params: params)
26
+ end
27
+
28
+ # Updates the name and/or HTML content of a template. Only updates imported
29
+ # HTML templates; does not currently update drag & drop templates
30
+ # @param template_id [String] The id of the email template
31
+ # @param :name [String] The name of the email template
32
+ # @param :html [String] The HTML content for this template
33
+ # @return [JSON] a JSON object containing information about the email template
34
+ def self.update_template(template_id, name:, html:)
35
+ path = "#{EMAIL_TEMPLATE}/#{template_id}"
36
+ params = {
37
+ name: name,
38
+ html: html
39
+ }
40
+ v1_request(HTTP_PUT, path, **params)
41
+ end
42
+
43
+ # Deletes a given template.
44
+ # @param template_id [String] The id of the email template
45
+ # @return [JSON] a JSON object containing information about the email template
46
+ def self.delete_template(template_id)
47
+ path = "#{EMAIL_TEMPLATE}/#{template_id}"
48
+ v1_request(HTTP_DELETE, path)
49
+ end
50
+
51
+ # Creates a copy of a given template with a new name
52
+ # @param template_id [String] The id of the email template to copy
53
+ # @param :name [String] The name of the newly cloned email template
54
+ # @return [JSON] a JSON object containing information about the email template
55
+ def self.clone_template(template_id, name:)
56
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{CLONE}"
57
+ params = {
58
+ name: name
59
+ }
60
+ v1_request(HTTP_POST, path, content_type: CONTENT_URL_FORM, params: params)
61
+ end
62
+
63
+ # Renders the specified template with the provided data and return HTML
64
+ # and text versions of the email
65
+ # @param template_id [String] The id of the email template to copy
66
+ # @param :context [Hash] The context the email template will be rendered with
67
+ # @return [JSON] a JSON object containing information about the email template
68
+ def self.render_template(template_id, context: {})
69
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{RENDER}"
70
+ params = {
71
+ context: context
72
+ }
73
+ v1_request(HTTP_POST, path, content_type: CONTENT_URL_FORM, params: params)
74
+ end
75
+
76
+ # Renders the specified template with the provided data and then send the
77
+ # contents in an email via the service specified
78
+ # @param template_id [String] The id of the email template to copy
79
+ # @param :from_email [String] The from email address; used in the reply-to header
80
+ # @param :from_name [String] The name the email is sent from
81
+ # @param :subject [String] The subject of the email template
82
+ # @param :to [Mixed] The email this template is being sent to
83
+ # @param :context [Hash] The context the email template will be rendered with
84
+ # @return [JSON] a JSON object containing information about the email template
85
+ def self.send_template(template_id, from_email:, from_name:, subject:, to:, context: {})
86
+ path = "#{EMAIL_TEMPLATE}/#{template_id}/#{SEND}"
87
+ params = {
88
+ from_email: from_email,
89
+ from_name: from_name,
90
+ subject: subject,
91
+ to: to,
92
+ context: context
93
+ }
94
+ v1_request(HTTP_POST, path, content_type: CONTENT_URL_FORM, params: params)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,166 @@
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
+ # @return will return with HTTP OK on success
13
+ def self.create_list(list_name)
14
+ body = {
15
+ :list_name => list_name
16
+ }
17
+ v2_request(HTTP_POST, LISTS, **body)
18
+ end
19
+
20
+ # Retrieves all the lists in the Klaviyo account
21
+ # @return [List] a list of JSON objects of the name and id for each list
22
+ def self.get_lists()
23
+ v2_request(HTTP_GET, LISTS)
24
+ end
25
+
26
+ # Retrieves the details of the list
27
+ # @param list_id [String] the id of the list
28
+ # @return [JSON] a JSON object containing information about the list
29
+ def self.get_list_details(list_id)
30
+ path = "#{LIST}/#{list_id}"
31
+ v2_request(HTTP_GET, path)
32
+ end
33
+
34
+ # Updates the properties of a list
35
+ # @param list_id [String] the id of the list
36
+ # @param list_name [String] the new name of the list
37
+ # @return will return with HTTP OK on success
38
+ def self.update_list_details(list_id, list_name)
39
+ path = "#{LIST}/#{list_id}"
40
+ body = {
41
+ :list_name => list_name
42
+ }
43
+ v2_request(HTTP_PUT, path, **body)
44
+ end
45
+
46
+ # Deletes a list
47
+ # @param list_id [String] the id of the list
48
+ # @return will return with HTTP OK on success
49
+ def self.delete_list(list_id)
50
+ path = "#{LIST}/#{list_id}"
51
+ v2_request(HTTP_DELETE, path)
52
+ end
53
+
54
+ # Check if profiles are in a list and not supressed
55
+ # @param list_id [String] the id of the list
56
+ # @param :emails [List] the emails of the profiles to check
57
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
58
+ # @param :push_tokens [List] push tokens of the profiles to check
59
+ # @return A list of JSON objects of the profiles. Profiles that are
60
+ # supressed or not found are not included.
61
+ def self.check_list_subscriptions(list_id, emails: [], phone_numbers: [], push_tokens: [])
62
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
63
+ params = {
64
+ :emails => emails,
65
+ :phone_numbers => phone_numbers,
66
+ :push_tokens => push_tokens
67
+ }
68
+ v2_request(HTTP_GET, path, **params)
69
+ end
70
+
71
+ # Subscribe profiles to a list.
72
+ # @param list_id [String] the id of the list
73
+ # @param profiles [List] a list of JSON objects. Each object requires either
74
+ # an email or phone number key.
75
+ # @return will retun HTTP OK on success. If the list is single opt-in then a
76
+ # list of records containing the email address, phone number, push token,
77
+ # and the corresponding profile ID will also be included.
78
+ def self.add_subscribers_to_list(list_id, profiles: [])
79
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
80
+ params = {
81
+ :profiles => profiles
82
+ }
83
+ v2_request(HTTP_POST, path, **params)
84
+ end
85
+
86
+ # Unsubscribe and remove profiles from a list
87
+ # @param list_id [String] the id of the list
88
+ # @param :emails [List] the emails of the profiles to check
89
+ # @return will return with HTTP OK on success
90
+ def self.unsubscribe_from_list(list_id, emails: [])
91
+ path = "#{LIST}/#{list_id}/#{SUBSCRIBE}"
92
+ params = {
93
+ :emails => emails
94
+ }
95
+ v2_request(HTTP_DELETE, path, **params)
96
+ end
97
+
98
+ # Add profiles to a list
99
+ # @param list_id [String] the id of the list
100
+ # @param :profiles [List] A list of JSON objects. Each object is a profile
101
+ # that will be added to the list
102
+ # @return will return with HTTP OK on success and a list of records of the
103
+ # corresponding profile id
104
+ def self.add_to_list(list_id, profiles: [])
105
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
106
+ params = {
107
+ :profiles => profiles
108
+ }
109
+ v2_request(HTTP_POST, path, **params)
110
+ end
111
+
112
+ # Check if profiles are on a list
113
+ # @param list_id [String] the id of the list
114
+ # @param :emails [List] the emails of the profiles to check
115
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
116
+ # @param :push_tokens [List] push tokens of the profiles to check
117
+ # @return A list of JSON objects of the profiles. Profiles that are
118
+ # supressed or not found are not included.
119
+ def self.check_list_memberships(list_id, emails: [], phone_numbers: [], push_tokens: [])
120
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
121
+ params = {
122
+ :emails => emails,
123
+ :phone_numbers => phone_numbers,
124
+ :push_tokens => push_tokens
125
+ }
126
+ v2_request(HTTP_GET, path, **params)
127
+ end
128
+
129
+ # Remove profiles from a list
130
+ # @param list_id [String] the id of the list
131
+ # @param :emails [List] the emails of the profiles to check
132
+ # @param :phone_numbers [List] the phone numbers of the profiles to check
133
+ # @param :push_tokens [List] push tokens of the profiles to check
134
+ # @return will return with HTTP OK on success
135
+ def self.remove_from_list(list_id, emails: [], phone_numbers: [], push_tokens: [])
136
+ path = "#{LIST}/#{list_id}/#{MEMBERS}"
137
+ params = {
138
+ :emails => emails,
139
+ :phone_numbers => phone_numbers,
140
+ :push_tokens => push_tokens
141
+ }
142
+ v2_request(HTTP_DELETE, path, **params)
143
+ end
144
+
145
+ # Get all emails, phone numbers, along with reasons for list exclusion
146
+ # @param list_id [String] the id of the list
147
+ # @param marker [Integer] a marker from a previous call to get the next batch
148
+ # @return [List] A list of JSON object for each profile with the reason for exclusion
149
+ def self.get_list_exclusions(list_id, marker: nil)
150
+ path = "#{LIST}/#{list_id}/#{EXCLUSIONS}/#{ALL}"
151
+ params = {
152
+ :marker => marker
153
+ }
154
+ v2_request(HTTP_GET, path, **params)
155
+ end
156
+
157
+ # Get all of the emails, phone numbers, and push tokens for profiles in a given list or segment
158
+ # @param list_id [String] the id of the list
159
+ # @param marker [Integer] a marker from a previous call to get the next batch
160
+ # @return [List] A list of JSON objects for each profile with the id, email, phone number, and push token
161
+ def self.get_group_members(list_id)
162
+ path = "#{GROUP}/#{list_id}/#{MEMBERS}/#{ALL}"
163
+ v2_request(HTTP_GET, path)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,80 @@
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
+ # @return a dictionary with a data property that contains an array of all the metrics
9
+ def self.get_metrics(page: DEFAULT_PAGE, count: DEFAULT_COUNT)
10
+ params = {
11
+ :page => page,
12
+ :count => count
13
+ }
14
+ v1_request(HTTP_GET, METRICS, **params)
15
+ end
16
+
17
+ # Returns a batched timeline of all events in your Klaviyo account.
18
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
19
+ # @param count [Integer] number of results to return, default 100
20
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
21
+ # @return a dictionary with a data property that contains an array of the metrics
22
+ def self.get_metrics_timeline(since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
23
+ path = "#{METRICS}/#{TIMELINE}"
24
+ params = {
25
+ :since => since,
26
+ :count => count,
27
+ :sort => sort
28
+ }
29
+ v1_request(HTTP_GET, path, **params)
30
+ end
31
+
32
+ # Returns a batched timeline for one specific type of metric.
33
+ # @param metric_id [String] the id of the metric
34
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
35
+ # @param count [Integer] number of results to return, default 100
36
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
37
+ # @return a dictionary with a data property that contains information about what metric the event tracks
38
+ def self.get_metric_timeline(metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
39
+ path = "#{METRIC}/#{metric_id}/#{TIMELINE}"
40
+ params = {
41
+ :since => since,
42
+ :count => count,
43
+ :sort => sort
44
+ }
45
+ v1_request(HTTP_GET, path, **params)
46
+ end
47
+
48
+ # Export event data, optionally filtering and segmented on available event properties
49
+ # @param metric_id [String] the id of the metric
50
+ # @param start_date [String] Beginning of the timeframe to pull event data for. Default is 1 month ago
51
+ # @param end_date [String] End of the timeframe to pull event data for. Default is the current day
52
+ # @param unit [String] Granularity to bucket data points into - one of ‘day’, ‘week’, or ‘month’. Defaults to ‘day’.
53
+ # @param measurement [String or JSON-encoded list] Type of metric to fetch
54
+ # @param where [JSON-encoded list] Conditions to use to filter the set of events. A max of 1 condition can be given.
55
+ # @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.
56
+ # @param count [Integer] Maximum number of segments to return. The default value is 25.
57
+ # @return A dictionary relecting the input request parameters as well as a results property
58
+ def self.get_metric_export(metric_id,
59
+ start_date: nil,
60
+ end_date: nil,
61
+ unit: nil,
62
+ measurement: nil,
63
+ where: nil,
64
+ by: nil,
65
+ count: nil
66
+ )
67
+ path = "#{METRIC}/#{metric_id}/#{EXPORT}"
68
+ params = {
69
+ :start_date => start_date,
70
+ :end_date => end_date,
71
+ :unit => unit,
72
+ :measurement => measurement,
73
+ :where => where,
74
+ :by => by,
75
+ :count => count
76
+ }
77
+ v1_request(HTTP_GET, path, **params)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,68 @@
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
+ # @return [JSON] a JSON object containing id of the profile
10
+ def self.get_profile_id_by_email(email)
11
+ path = "#{PEOPLE}/#{SEARCH}"
12
+ params = {
13
+ :email => email
14
+ }
15
+ v2_request(HTTP_GET, path, **params)
16
+ end
17
+
18
+ # Retrieve all the data attributes for a Klaviyo Person ID.
19
+ # @param person_id [String] the id of the profile
20
+ # @return returns a person object
21
+ def self.get_person_attributes(person_id)
22
+ path = "#{PERSON}/#{person_id}"
23
+ v1_request(HTTP_GET, path)
24
+ end
25
+
26
+ # Add or update one more more attributes for a Person
27
+ # @param person_id [String] the id of the profile
28
+ # @param kwargs [Key/value pairs] attributes to add/update in the profile
29
+ # @return returns the updated person object
30
+ def self.update_person_attributes(person_id, kwargs = {})
31
+ path = "#{PERSON}/#{person_id}"
32
+ v1_request(HTTP_PUT, path, **kwargs)
33
+ end
34
+
35
+ # Listing a person's event timeline
36
+ # @param person_id [String] the id of the profile
37
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
38
+ # @param count [Integer] number of results to return, default 100
39
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
40
+ # @return returns a dictionary containing a list of metric event objects
41
+ def self.get_person_metrics_timeline(person_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
42
+ path = "#{PERSON}/#{person_id}/#{METRICS}/#{TIMELINE}"
43
+ params = {
44
+ :since => since,
45
+ :count => count,
46
+ :sort => sort
47
+ }
48
+ v1_request(HTTP_GET, path, **params)
49
+ end
50
+
51
+ # Listing a person's event timeline for a particular metric
52
+ # @param person_id [String] the id of the profile
53
+ # @param metric_id [String] the id of the metric
54
+ # @param since [Integer or String] either a Unix timestamp or the UUID from a previous request. Default is the current time.
55
+ # @param count [Integer] number of results to return, default 100
56
+ # @param sort [String] 'asc' or 'desc', sort order to apply to the timeline. Default is 'desc'.
57
+ # @return returns a dictionary containing a list of metric event objects
58
+ def self.get_person_metric_timeline(person_id, metric_id, since: nil, count: DEFAULT_COUNT, sort: DEFAULT_SORT_DESC)
59
+ path = "#{PERSON}/#{person_id}/#{METRIC}/#{metric_id}/#{TIMELINE}"
60
+ params = {
61
+ :since => since,
62
+ :count => count,
63
+ :sort => sort
64
+ }
65
+ v1_request(HTTP_GET, path, **params)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,84 @@
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
+ # @kwargs :method [String] the HTTP method to use for the request. Accepts 'get' or 'post'. Defaults to 'get'.
10
+ def self.identify(kwargs = {})
11
+ defaults = {:id => nil,
12
+ :email => nil,
13
+ :phone_number => nil,
14
+ :properties => {},
15
+ :method => HTTP_GET
16
+ }
17
+ kwargs = defaults.merge(kwargs)
18
+
19
+ unless check_required_args(kwargs)
20
+ return
21
+ end
22
+
23
+ properties = kwargs[:properties]
24
+ properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
25
+ properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
26
+ properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
27
+
28
+ params = {
29
+ :token => Klaviyo.public_api_key,
30
+ :properties => properties
31
+ }
32
+
33
+ public_request(kwargs[:method], 'identify', **params)
34
+ end
35
+
36
+ # Used for tracking events and customer behaviors
37
+ #
38
+ # @param event [String] the event to track
39
+ # @kwarg :id [String] the customer or profile id
40
+ # @kwarg :email [String] the customer or profile email
41
+ # @kwarg :phone_number [String] the customer or profile phone number
42
+ # @kwarg :properties [Hash] properties of the event
43
+ # @kwargs :customer_properties [Hash] properties of the customer or profile
44
+ # @kwargs :time [Integer] timestamp of the event
45
+ # @kwargs :method [String] the HTTP method to use for the request. Accepts 'get' or 'post'. Defaults to 'get'.
46
+ def self.track(event, kwargs = {})
47
+ defaults = {
48
+ :id => nil,
49
+ :email => nil,
50
+ :phone_number => nil,
51
+ :properties => {},
52
+ :customer_properties => {},
53
+ :time => nil,
54
+ :method => HTTP_GET
55
+ }
56
+
57
+ kwargs = defaults.merge(kwargs)
58
+
59
+ unless check_required_args(kwargs)
60
+ return
61
+ end
62
+
63
+ customer_properties = kwargs[:customer_properties]
64
+ customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
65
+ customer_properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
66
+ customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
67
+
68
+ params = {
69
+ :token => Klaviyo.public_api_key,
70
+ :event => event,
71
+ :properties => kwargs[:properties],
72
+ :customer_properties => customer_properties
73
+ }
74
+ params[:time] = kwargs[:time] if kwargs[:time]
75
+
76
+ public_request(kwargs[:method], 'track', **params)
77
+ end
78
+
79
+ def self.track_once(event, kwargs = {})
80
+ kwargs.update('__track_once__' => true)
81
+ track(event, kwargs)
82
+ end
83
+ end
84
+ end
@@ -1,74 +1,131 @@
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
- def initialize(api_key, url = 'http://a.klaviyo.com/')
10
- @api_key = api_key
11
- @url = url
3
+ BASE_API_URL = 'https://a.klaviyo.com/api'
4
+ V1_API = 'v1'
5
+ V2_API = 'v2'
6
+
7
+ HTTP_DELETE = 'delete'
8
+ HTTP_GET = 'get'
9
+ HTTP_POST = 'post'
10
+ HTTP_PUT = 'put'
11
+
12
+ ALL = 'all'
13
+ METRIC = 'metric'
14
+ METRICS = 'metrics'
15
+ TIMELINE = 'timeline'
16
+
17
+ DEFAULT_COUNT = 100
18
+ DEFAULT_PAGE = 0
19
+ DEFAULT_SORT_DESC = 'desc'
20
+
21
+ CONTENT_JSON = 'application/json'
22
+ CONTENT_URL_FORM = 'application/x-www-form-urlencoded'
23
+
24
+ private
25
+
26
+ def self.request(method, path, content_type, **kwargs)
27
+ check_private_api_key_exists()
28
+ url = "#{BASE_API_URL}/#{path}"
29
+ connection = Faraday.new(
30
+ url: url,
31
+ headers: {
32
+ 'Content-Type' => content_type
33
+ })
34
+ if content_type == CONTENT_JSON
35
+ kwargs[:body] = kwargs[:body].to_json
36
+ end
37
+ response = connection.send(method) do |req|
38
+ req.body = kwargs[:body] || nil
39
+ end
40
+ end
41
+
42
+ def self.public_request(method, path, **kwargs)
43
+ check_public_api_key_is_valid()
44
+ if method == HTTP_GET
45
+ params = build_params(kwargs)
46
+ url = "#{BASE_API_URL}/#{path}?#{params}"
47
+ res = Faraday.get(url).body
48
+ elsif method == HTTP_POST
49
+ url = URI("#{BASE_API_URL}/#{path}")
50
+ response = Faraday.post(url) do |req|
51
+ req.headers['Content-Type'] = CONTENT_URL_FORM
52
+ req.headers['Accept'] = 'text/html'
53
+ req.body = {data: "#{kwargs.to_json}"}
54
+ end
55
+ else
56
+ raise KlaviyoError.new(INVALID_HTTP_METHOD)
57
+ end
12
58
  end
13
-
14
- def track(event, kwargs = {})
15
- defaults = {:id => nil, :email => nil, :properties => {}, :customer_properties => {}, :time => nil}
16
- kwargs = defaults.merge(kwargs)
17
-
18
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
19
- raise KlaviyoError.new('You must identify a user by email or ID')
59
+
60
+ def self.v1_request(method, path, content_type: CONTENT_JSON, **kwargs)
61
+ if content_type == CONTENT_URL_FORM
62
+ data = {
63
+ :body => {
64
+ :api_key => Klaviyo.private_api_key
65
+ }
66
+ }
67
+ data[:body] = data[:body].merge(kwargs[:params])
68
+ full_url = "#{V1_API}/#{path}"
69
+ request(method, full_url, content_type, **data)
70
+ else
71
+ defaults = {:page => nil,
72
+ :count => nil,
73
+ :since => nil,
74
+ :sort => nil}
75
+ params = defaults.merge(kwargs)
76
+ query_params = encode_params(params)
77
+ full_url = "#{V1_API}/#{path}?api_key=#{Klaviyo.private_api_key}#{query_params}"
78
+ request(method, full_url, content_type)
20
79
  end
21
-
22
- customer_properties = kwargs[:customer_properties]
23
- customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
24
- customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
80
+ end
25
81
 
26
- params = {
27
- :token => @api_key,
28
- :event => event,
29
- :properties => kwargs[:properties],
30
- :customer_properties => customer_properties,
31
- :ip => ''
82
+ def self.v2_request(method, path, **kwargs)
83
+ path = "#{V2_API}/#{path}"
84
+ key = {
85
+ "api_key": "#{Klaviyo.private_api_key}"
32
86
  }
33
- params[:time] = kwargs[:time].to_time.to_i if kwargs[:time]
34
-
35
- params = build_params(params)
36
- request('crm/api/track', params)
87
+ data = {}
88
+ data[:body] = key.merge(kwargs)
89
+ request(method, path, CONTENT_JSON, **data)
37
90
  end
38
-
39
- def track_once(event, opts = {})
40
- opts.update('__track_once__' => true)
41
- track(event, opts)
91
+
92
+ def self.build_params(params)
93
+ "data=#{CGI.escape(Base64.encode64(JSON.generate(params)).gsub(/\n/, ''))}"
42
94
  end
43
-
44
- def identify(kwargs = {})
45
- defaults = {:id => nil, :email => nil, :properties => {}}
46
- kwargs = defaults.merge(kwargs)
47
-
48
- if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
49
- raise KlaviyoError.new('You must identify a user by email or ID')
95
+
96
+ def self.check_required_args(kwargs)
97
+ if kwargs[:email].to_s.empty? and kwargs[:phone_number].to_s.empty? and kwargs[:id].to_s.empty?
98
+ raise Klaviyo::KlaviyoError.new(REQUIRED_ARG_ERROR)
99
+ else
100
+ return true
50
101
  end
51
-
52
- properties = kwargs[:properties]
53
- properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
54
- properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
102
+ end
55
103
 
56
- params = build_params({
57
- :token => @api_key,
58
- :properties => properties
59
- })
60
- request('crm/api/identify', params)
104
+ def self.check_private_api_key_exists()
105
+ if !Klaviyo.private_api_key
106
+ raise KlaviyoError.new(NO_PRIVATE_API_KEY_ERROR)
107
+ end
61
108
  end
62
109
 
63
- private
64
-
65
- def build_params(params)
66
- 'data=' + Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
110
+ def self.check_public_api_key_is_valid()
111
+ if !Klaviyo.public_api_key
112
+ raise KlaviyoError.new(NO_PUBLIC_API_KEY_ERROR)
113
+ end
114
+ if ( Klaviyo.public_api_key =~ /pk_\w{34}$/ ) == 0
115
+ raise KlaviyoError.new(PRIVATE_KEY_AS_PUBLIC)
116
+ end
117
+ if ( Klaviyo.public_api_key =~ /\w{6}$/ ) != 0
118
+ raise KlaviyoError.new(INCORRECT_PUBLIC_API_KEY_LENGTH)
119
+ end
67
120
  end
68
-
69
- def request(path, params)
70
- url = @url + path + '?' + params
71
- open(url).read == '1' ? true : false
121
+
122
+ def self.encode_params(kwargs)
123
+ kwargs.select!{|k, v| v}
124
+ params = URI.encode_www_form(kwargs)
125
+
126
+ if !params.empty?
127
+ return "&#{params}"
128
+ end
72
129
  end
73
130
  end
74
131
  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'
metadata CHANGED
@@ -1,88 +1,109 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klaviyo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Klaviyo Team
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-06 00:00:00.000000000 Z
11
+ date: 2021-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: escape
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
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
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
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
- - lib/klaviyo/client.rb
63
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
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: []
67
89
  metadata: {}
68
- post_install_message:
90
+ post_install_message:
69
91
  rdoc_options: []
70
92
  require_paths:
71
93
  - lib
72
94
  required_ruby_version: !ruby/object:Gem::Requirement
73
95
  requirements:
74
- - - '>='
96
+ - - ">="
75
97
  - !ruby/object:Gem::Version
76
98
  version: '0'
77
99
  required_rubygems_version: !ruby/object:Gem::Requirement
78
100
  requirements:
79
- - - '>='
101
+ - - ">="
80
102
  - !ruby/object:Gem::Version
81
103
  version: '0'
82
104
  requirements: []
83
- rubyforge_project:
84
- rubygems_version: 2.0.14
85
- signing_key:
105
+ rubygems_version: 3.0.8
106
+ signing_key:
86
107
  specification_version: 4
87
108
  summary: You heard us, a Ruby wrapper for the Klaviyo API
88
109
  test_files: []