klaviyo 2.0.6 → 0.9.4

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.
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 = '2.0.6'
6
- s.date = '2021-04-08'
5
+ s.version = '0.9.4'
6
+ s.date = '2012-09-06'
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
- s.authors = ['Klaviyo Team']
10
- s.email = 'libraries@klaviyo.com'
9
+ s.authors = ['Andrew Bialecki']
10
+ s.email = 'andrew@klaviyo.com'
11
11
  s.files = files
12
- s.homepage = 'https://www.klaviyo.com/'
12
+ s.homepage = 'http://www.klaviyo.com/'
13
13
  s.require_path = 'lib'
14
+ s.has_rdoc = false
14
15
  s.add_dependency 'json'
15
16
  s.add_dependency 'rack'
16
17
  s.add_dependency 'escape'
17
- s.add_dependency 'faraday'
18
18
  end
@@ -0,0 +1,72 @@
1
+ require 'rack'
2
+
3
+ module Klaviyo
4
+ class Client
5
+ class Middleware
6
+ def initialize(app, api_key, options={})
7
+ @app = app
8
+ @api_key = api_key
9
+ @options = {
10
+ :insert_js_last => true
11
+ }.merge(options)
12
+ end
13
+
14
+ def call(env)
15
+ @env = env
16
+
17
+ @status, @headers, @response = @app.call(env)
18
+
19
+ if is_trackable_response?
20
+ update_response!
21
+ update_content_length!
22
+ end
23
+
24
+ [@status, @headers, @response]
25
+ end
26
+
27
+ private
28
+
29
+ def update_response!
30
+ @response.each do |part|
31
+ insert_at = part.index(@options[:insert_js_last] ? '</body' : '</head')
32
+ unless insert_at.nil?
33
+ part.insert(insert_at, render_script)
34
+ end
35
+ end
36
+ end
37
+
38
+ def update_content_length!
39
+ new_size = 0
40
+ @response.each{|part| new_size += part.bytesize}
41
+ @headers.merge!('Content-Length' => new_size.to_s)
42
+ end
43
+
44
+ def is_ajax_request?
45
+ @env.has_key?('HTTP_X_REQUESTED_WITH') && @env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
46
+ end
47
+
48
+ def is_html_response?
49
+ @headers['Content-Type'].include?('text/html') if @headers.has_key?('Content-Type')
50
+ end
51
+
52
+ def is_trackable_response?
53
+ is_html_response? && !is_ajax_request?
54
+ end
55
+
56
+ def render_script
57
+ <<-EOT
58
+ <script text="text/javascript">
59
+ var _learnq = _learnq || [];
60
+ _learnq.push(['account', '#{@api_key}']);
61
+
62
+ (function () {
63
+ var b = document.createElement('script'); b.type = 'text/javascript'; b.async = true;
64
+ b.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'a.klaviyo.com/media/js/learnmarklet.js';
65
+ var a = document.getElementsByTagName('script')[0]; a.parentNode.insertBefore(b, a);
66
+ })();
67
+ </script>
68
+ EOT
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,114 +1,73 @@
1
+ require 'open-uri'
2
+ require 'base64'
3
+ require 'json'
4
+ require 'klaviyo/client/middleware'
5
+
1
6
  module Klaviyo
7
+ class KlaviyoError < StandardError; end
8
+
2
9
  class Client
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
10
+ def initialize(api_key, url = 'http://a.klaviyo.com/')
11
+ @api_key = api_key
12
+ @url = url
40
13
  end
41
-
42
- def self.public_request(method, path, **kwargs)
43
- check_public_api_key_exists()
44
- params = build_params(kwargs)
45
- url = "#{BASE_API_URL}/#{path}?#{params}"
46
- res = Faraday.get(url).body
47
- end
48
-
49
- def self.v1_request(method, path, content_type: CONTENT_JSON, **kwargs)
50
- if content_type == CONTENT_URL_FORM
51
- data = {
52
- :body => {
53
- :api_key => Klaviyo.private_api_key
54
- }
55
- }
56
- data[:body] = data[:body].merge(kwargs[:params])
57
- full_url = "#{V1_API}/#{path}"
58
- request(method, full_url, content_type, data)
59
- else
60
- defaults = {:page => nil,
61
- :count => nil,
62
- :since => nil,
63
- :sort => nil}
64
- params = defaults.merge(kwargs)
65
- query_params = encode_params(params)
66
- full_url = "#{V1_API}/#{path}?api_key=#{Klaviyo.private_api_key}#{query_params}"
67
- request(method, full_url, content_type)
14
+
15
+ def track(event, kwargs = {})
16
+ defaults = {:id => nil, :email => nil, :properties => {}, :customer_properties => {}, :time => nil}
17
+ kwargs = defaults.merge(kwargs)
18
+
19
+ if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
20
+ raise KlaviyoError.new('You must identify a user by email or ID')
68
21
  end
22
+
23
+ customer_properties = kwargs[:customer_properties]
24
+ customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
25
+ customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
26
+
27
+ params = build_params({
28
+ :token => @api_key,
29
+ :event => event,
30
+ :properties => kwargs[:properties],
31
+ :customer_properties => customer_properties,
32
+ :ip => ''
33
+ })
34
+ params[:time] = kwargs[:time].to_time.to_i if kwargs[:time]
35
+ request('crm/api/track', params)
69
36
  end
70
-
71
- def self.v2_request(method, path, **kwargs)
72
- path = "#{V2_API}/#{path}"
73
- key = {
74
- "api_key": "#{Klaviyo.private_api_key}"
75
- }
76
- data = {}
77
- data[:body] = key.merge(kwargs)
78
- request(method, path, CONTENT_JSON, data)
79
- end
80
-
81
- def self.build_params(params)
82
- "data=#{CGI.escape(Base64.encode64(JSON.generate(params)).gsub(/\n/, ''))}"
37
+
38
+ def track_once(event, opts = {})
39
+ opts.update('__track_once__' => true)
40
+ track(event, opts)
83
41
  end
84
-
85
- def self.check_required_args(kwargs)
86
- if kwargs[:email].to_s.empty? and kwargs[:phone_number].to_s.empty? and kwargs[:id].to_s.empty?
87
- raise Klaviyo::KlaviyoError.new(REQUIRED_ARG_ERROR)
88
- else
89
- return true
42
+
43
+ def identify(kwargs = {})
44
+ defaults = {:id => nil, :email => nil, :properties => {}}
45
+ kwargs = defaults.merge(kwargs)
46
+
47
+ if kwargs[:email].to_s.empty? and kwargs[:id].to_s.empty?
48
+ raise KlaviyoError.new('You must identify a user by email or ID')
90
49
  end
91
- end
50
+
51
+ properties = kwargs[:properties]
52
+ properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
53
+ properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
92
54
 
93
- def self.check_private_api_key_exists()
94
- if !Klaviyo.private_api_key
95
- raise KlaviyoError.new(NO_PRIVATE_API_KEY_ERROR)
96
- end
55
+ params = build_params({
56
+ :token => @api_key,
57
+ :properties => properties
58
+ })
59
+ request('crm/api/identify', params)
97
60
  end
98
61
 
99
- def self.check_public_api_key_exists()
100
- if !Klaviyo.public_api_key
101
- raise KlaviyoError.new(NO_PUBLIC_API_KEY_ERROR)
102
- end
62
+ private
63
+
64
+ def build_params(params)
65
+ 'data=' + Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
103
66
  end
104
-
105
- def self.encode_params(kwargs)
106
- kwargs.select!{|k, v| v}
107
- params = URI.encode_www_form(kwargs)
108
-
109
- if !params.empty?
110
- return "&#{params}"
111
- end
67
+
68
+ def request(path, params)
69
+ url = @url + path + '?' + params
70
+ open(url).read == '1' ? true : false
112
71
  end
113
72
  end
114
73
  end
data/lib/klaviyo.rb CHANGED
@@ -1 +1 @@
1
- require 'klaviyo/klaviyo_module'
1
+ require 'klaviyo/client'
metadata CHANGED
@@ -1,109 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klaviyo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.6
4
+ version: 0.9.4
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
- - Klaviyo Team
8
- autorequire:
8
+ - Andrew Bialecki
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2021-04-08 00:00:00.000000000 Z
12
+ date: 2012-09-06 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: json
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - ">="
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - ">="
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rack
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - ">="
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: '0'
34
38
  type: :runtime
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - ">="
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: '0'
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: escape
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - ">="
51
+ - - ! '>='
46
52
  - !ruby/object:Gem::Version
47
53
  version: '0'
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
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
- - - ">="
59
+ - - ! '>='
67
60
  - !ruby/object:Gem::Version
68
61
  version: '0'
69
62
  description: Ruby wrapper for the Klaviyo API
70
- email: libraries@klaviyo.com
63
+ email: andrew@klaviyo.com
71
64
  executables: []
72
65
  extensions: []
73
66
  extra_rdoc_files: []
74
67
  files:
75
68
  - klaviyo.gemspec
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
69
+ - lib/klaviyo/client/middleware.rb
84
70
  - lib/klaviyo/client.rb
85
- - lib/klaviyo/klaviyo_module.rb
86
- - lib/rack/klaviyo.rb
87
- homepage: https://www.klaviyo.com/
71
+ - lib/klaviyo.rb
72
+ homepage: http://www.klaviyo.com/
88
73
  licenses: []
89
- metadata: {}
90
- post_install_message:
74
+ post_install_message:
91
75
  rdoc_options: []
92
76
  require_paths:
93
77
  - lib
94
78
  required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
95
80
  requirements:
96
- - - ">="
81
+ - - ! '>='
97
82
  - !ruby/object:Gem::Version
98
83
  version: '0'
99
84
  required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
100
86
  requirements:
101
- - - ">="
87
+ - - ! '>='
102
88
  - !ruby/object:Gem::Version
103
89
  version: '0'
104
90
  requirements: []
105
- rubygems_version: 3.0.8
106
- signing_key:
107
- specification_version: 4
91
+ rubyforge_project:
92
+ rubygems_version: 1.8.24
93
+ signing_key:
94
+ specification_version: 3
108
95
  summary: You heard us, a Ruby wrapper for the Klaviyo API
109
96
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA256:
3
- metadata.gz: c50780aa07007d13ffcbfd5e88692dc46122641627511be21f4988012d48d20e
4
- data.tar.gz: 453757a911094db7394000a2aa59d4a0f31a3cb6aa9196e50a749dac3e51b336
5
- SHA512:
6
- metadata.gz: 62278b5560afe418dc8658e71646f36905cdb10c2b607b923377ea08c8ea247630fc782c6dbceda1d4fe2a88f5f332995abce6dcf90484cfbc1791516d4b6cd3
7
- data.tar.gz: 1358f2f45b1e92144f8a43f0f52a291f3ee859af3e416924e003a1b7c7a02553965d6240fecf8289eb41167c422565c8909b57344b8baed9091c6f022801183b
@@ -1,41 +0,0 @@
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
@@ -1,19 +0,0 @@
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
- identifier = { id_type => identifier }
15
- path = "#{DATA_PRIVACY}/#{DELETION_REQUEST}"
16
- v2_request(HTTP_POST, path, identifier)
17
- end
18
- end
19
- end
@@ -1,97 +0,0 @@
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
@@ -1,166 +0,0 @@
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
@@ -1,80 +0,0 @@
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
@@ -1,68 +0,0 @@
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
@@ -1,79 +0,0 @@
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 :properties [Hash] properties of the profile to add or update
8
- def self.identify(kwargs = {})
9
- defaults = {:id => nil,
10
- :email => nil,
11
- :phone_number => nil,
12
- :properties => {}
13
- }
14
- kwargs = defaults.merge(kwargs)
15
-
16
- unless check_required_args(kwargs)
17
- return
18
- end
19
-
20
- properties = kwargs[:properties]
21
- properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
22
- properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
23
- properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
24
-
25
- params = {
26
- :token => Klaviyo.public_api_key,
27
- :properties => properties
28
- }
29
-
30
- public_request(HTTP_GET, 'identify', params)
31
- end
32
-
33
- # Used for tracking events and customer behaviors
34
- #
35
- # @param event [String] the event to track
36
- # @kwarg :id [String] the customer or profile id
37
- # @kwarg :email [String] the customer or profile email
38
- # @kwarg :phone_number [String] the customer or profile phone number
39
- # @kwarg :properties [Hash] properties of the event
40
- # @kwargs :customer_properties [Hash] properties of the customer or profile
41
- # @kwargs :time [Integer] timestamp of the event
42
- def self.track(event, kwargs = {})
43
- defaults = {
44
- :id => nil,
45
- :email => nil,
46
- :phone_number => nil,
47
- :properties => {},
48
- :customer_properties => {},
49
- :time => nil
50
- }
51
-
52
- kwargs = defaults.merge(kwargs)
53
-
54
- unless check_required_args(kwargs)
55
- return
56
- end
57
-
58
- customer_properties = kwargs[:customer_properties]
59
- customer_properties[:email] = kwargs[:email] unless kwargs[:email].to_s.empty?
60
- customer_properties[:$phone_number] = kwargs[:phone_number] unless kwargs[:phone_number].to_s.empty?
61
- customer_properties[:id] = kwargs[:id] unless kwargs[:id].to_s.empty?
62
-
63
- params = {
64
- :token => Klaviyo.public_api_key,
65
- :event => event,
66
- :properties => kwargs[:properties],
67
- :customer_properties => customer_properties
68
- }
69
- params[:time] = kwargs[:time] if kwargs[:time]
70
-
71
- public_request(HTTP_GET, 'track', **params)
72
- end
73
-
74
- def self.track_once(event, kwargs = {})
75
- kwargs.update('__track_once__' => true)
76
- track(event, kwargs)
77
- end
78
- end
79
- end
@@ -1,27 +0,0 @@
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
- end
data/lib/rack/klaviyo.rb DELETED
@@ -1,68 +0,0 @@
1
- module Rack
2
- class Klaviyo
3
- def initialize(app, api_key, options={})
4
- @app = app
5
- @api_key = api_key
6
- @options = {
7
- :insert_js_last => true
8
- }.merge(options)
9
- end
10
-
11
- def call(env)
12
- @env = env
13
-
14
- @status, @headers, @response = @app.call(env)
15
-
16
- if is_trackable_response?
17
- update_response!
18
- update_content_length!
19
- end
20
-
21
- [@status, @headers, @response]
22
- end
23
-
24
- private
25
-
26
- def update_response!
27
- @response.each do |part|
28
- insert_at = part.index(@options[:insert_js_last] ? '</body' : '</head')
29
- unless insert_at.nil?
30
- part.insert(insert_at, render_script)
31
- end
32
- end
33
- end
34
-
35
- def update_content_length!
36
- new_size = 0
37
- @response.each{|part| new_size += part.bytesize}
38
- @headers.merge!('Content-Length' => new_size.to_s)
39
- end
40
-
41
- def is_ajax_request?
42
- @env.has_key?('HTTP_X_REQUESTED_WITH') && @env['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'
43
- end
44
-
45
- def is_html_response?
46
- @headers['Content-Type'].include?('text/html') if @headers.has_key?('Content-Type')
47
- end
48
-
49
- def is_trackable_response?
50
- is_html_response? && !is_ajax_request?
51
- end
52
-
53
- def render_script
54
- <<-EOT
55
- <script text="text/javascript">
56
- var _learnq = _learnq || [];
57
- _learnq.push(['account', '#{@api_key}']);
58
-
59
- (function () {
60
- var b = document.createElement('script'); b.type = 'text/javascript'; b.async = true;
61
- b.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'a.klaviyo.com/media/js/analytics/analytics.js';
62
- var a = document.getElementsByTagName('script')[0]; a.parentNode.insertBefore(b, a);
63
- })();
64
- </script>
65
- EOT
66
- end
67
- end
68
- end