sift 4.2.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +17 -0
- data/.github/workflows/publishing_sift_ruby.yml +38 -0
- data/.gitignore +1 -0
- data/.jenkins/Jenkinsfile +103 -0
- data/HISTORY +9 -0
- data/README.md +99 -2
- data/examples/psp_merchant_management_apis.rb +105 -0
- data/lib/sift/client.rb +132 -2
- data/lib/sift/version.rb +1 -1
- data/lib/sift.rb +12 -0
- data/spec/unit/client_psp_merchant_spec.rb +133 -0
- data/spec/unit/client_spec.rb +165 -0
- data/test_integration_app/decisions_api/test_decisions_api.rb +31 -0
- data/test_integration_app/events_api/test_events_api.rb +843 -0
- data/test_integration_app/globals.rb +2 -0
- data/test_integration_app/main.rb +67 -0
- data/test_integration_app/psp_merchants_api/test_psp_merchant_api.rb +44 -0
- data/test_integration_app/score_api/test_score_api.rb +11 -0
- data/test_integration_app/verification_api/test_verification_api.rb +32 -0
- metadata +15 -17
@@ -0,0 +1,133 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
require "sift"
|
3
|
+
|
4
|
+
describe Sift::Client do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
Sift.api_key = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def post_psp_merchant_properties
|
11
|
+
{
|
12
|
+
"id": "api-key1-6",
|
13
|
+
"name": "Wonderful Payments Inc.",
|
14
|
+
"description": "Wonderful Payments payment provider.",
|
15
|
+
"address": {
|
16
|
+
"name": "Alany",
|
17
|
+
"address_1": "Big Payment blvd, 22",
|
18
|
+
"address_2": "apt, 8",
|
19
|
+
"city": "New Orleans",
|
20
|
+
"region": "NA",
|
21
|
+
"country": "US",
|
22
|
+
"zipcode": "76830",
|
23
|
+
"phone": "0394888320"
|
24
|
+
},
|
25
|
+
"category": "1002",
|
26
|
+
"service_level": "Platinum",
|
27
|
+
"status": "active",
|
28
|
+
"risk_profile": {
|
29
|
+
"level": "low",
|
30
|
+
"score": 10
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def put_psp_merchant_properties
|
36
|
+
{
|
37
|
+
"id": "api-key1-7",
|
38
|
+
"name": "Wonderful Payments Inc.",
|
39
|
+
"description": "Wonderful Payments payment provider.",
|
40
|
+
"address": {
|
41
|
+
"name": "Alany",
|
42
|
+
"address_1": "Big Payment blvd, 22",
|
43
|
+
"address_2": "apt, 8",
|
44
|
+
"city": "New Orleans",
|
45
|
+
"region": "NA",
|
46
|
+
"country": "US",
|
47
|
+
"zipcode": "76830",
|
48
|
+
"phone": "0394888320"
|
49
|
+
},
|
50
|
+
"category": "1002",
|
51
|
+
"service_level": "Platinum",
|
52
|
+
"status": "active",
|
53
|
+
"risk_profile": {
|
54
|
+
"level": "low",
|
55
|
+
"score": 10
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
it "Successfully sumit create psp merchant" do
|
61
|
+
api_key = "foobar1"
|
62
|
+
|
63
|
+
response_json = { :status => 0, :error_message => "OK" }
|
64
|
+
|
65
|
+
stub_request(:post, "https://foobar1:@api.siftscience.com/v3/accounts/ACCT/psp_management/merchants")
|
66
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
67
|
+
|
68
|
+
response = Sift::Client.new(:api_key => api_key, :account_id => "ACCT").create_psp_merchant_profile(post_psp_merchant_properties)
|
69
|
+
expect(response.ok?).to eq(true)
|
70
|
+
expect(response.api_status).to eq(0)
|
71
|
+
expect(response.api_error_message).to eq("OK")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "Successfully submit update psp merchant" do
|
75
|
+
api_key = "foobar1"
|
76
|
+
merchant_id = "api-key1-7"
|
77
|
+
|
78
|
+
response_json = { :status => 0, :error_message => "OK"}
|
79
|
+
|
80
|
+
stub_request(:put, "https://foobar1:@api.siftscience.com/v3/accounts/ACCT/psp_management/merchants/api-key1-7")
|
81
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
82
|
+
|
83
|
+
response = Sift::Client.new(:api_key => api_key, :account_id => "ACCT").update_psp_merchant_profile(merchant_id, put_psp_merchant_properties)
|
84
|
+
expect(response.ok?).to eq(true)
|
85
|
+
expect(response.api_status).to eq(0)
|
86
|
+
expect(response.api_error_message).to eq("OK")
|
87
|
+
end
|
88
|
+
|
89
|
+
it "Successfully get a psp merchant profile" do
|
90
|
+
api_key = "foobar1"
|
91
|
+
merchant_id = "api-key1-7"
|
92
|
+
|
93
|
+
response_json = { :status => 0, :error_message => "OK"}
|
94
|
+
|
95
|
+
stub_request(:get, "https://foobar1:@api.siftscience.com/v3/accounts/ACCT/psp_management/merchants/api-key1-7")
|
96
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
97
|
+
|
98
|
+
response = Sift::Client.new(:api_key => api_key, :account_id => "ACCT").get_a_psp_merchant_profile(merchant_id)
|
99
|
+
expect(response.ok?).to eq(true)
|
100
|
+
expect(response.api_status).to eq(0)
|
101
|
+
expect(response.api_error_message).to eq("OK")
|
102
|
+
end
|
103
|
+
|
104
|
+
it "Successfully get all psp merchant profile with batch size" do
|
105
|
+
api_key = "foobar1"
|
106
|
+
|
107
|
+
response_json = { :status => 0, :error_message => "OK"}
|
108
|
+
|
109
|
+
stub_request(:get, "https://foobar1:@api.siftscience.com/v3/accounts/ACCT/psp_management/merchants?batch_size=2")
|
110
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
111
|
+
|
112
|
+
response = Sift::Client.new(:api_key => api_key, :account_id => "ACCT").get_psp_merchant_profiles(2)
|
113
|
+
expect(response.ok?).to eq(true)
|
114
|
+
expect(response.api_status).to eq(0)
|
115
|
+
expect(response.api_error_message).to eq("OK")
|
116
|
+
end
|
117
|
+
|
118
|
+
it "Successfully get all psp merchant profile with batch size and batch token" do
|
119
|
+
api_key = "foobar1"
|
120
|
+
batch_size = 2
|
121
|
+
batch_token = "batch_token"
|
122
|
+
response_json = { :status => 0, :error_message => "OK"}
|
123
|
+
|
124
|
+
stub_request(:get, "https://foobar1:@api.siftscience.com/v3/accounts/ACCT/psp_management/merchants?batch_size=2&batch_token=batch_token")
|
125
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json))
|
126
|
+
|
127
|
+
response = Sift::Client.new(:api_key => api_key, :account_id => "ACCT").get_psp_merchant_profiles(batch_size, batch_token)
|
128
|
+
expect(response.ok?).to eq(true)
|
129
|
+
expect(response.api_status).to eq(0)
|
130
|
+
expect(response.api_error_message).to eq("OK")
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
data/spec/unit/client_spec.rb
CHANGED
@@ -110,6 +110,69 @@ describe Sift::Client do
|
|
110
110
|
}
|
111
111
|
end
|
112
112
|
|
113
|
+
def warnings
|
114
|
+
{
|
115
|
+
:count => 1,
|
116
|
+
:items => [{
|
117
|
+
:message => 'Invalid currency'
|
118
|
+
}]
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def percentile_response_json
|
123
|
+
{
|
124
|
+
:user_id => 'billy_jones_301',
|
125
|
+
:latest_labels => {},
|
126
|
+
:workflow_statuses => [],
|
127
|
+
:scores => {
|
128
|
+
:account_abuse => {
|
129
|
+
:score => 0.32787917675535705,
|
130
|
+
:reasons => [{
|
131
|
+
:name => 'Latest item product title',
|
132
|
+
:value => 'The Slanket Blanket-Texas Tea'
|
133
|
+
}],
|
134
|
+
:percentiles => {
|
135
|
+
:last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
|
136
|
+
}
|
137
|
+
},
|
138
|
+
:acontent_abuse => {
|
139
|
+
:score => 0.28056292905897995,
|
140
|
+
:reasons => [{
|
141
|
+
:name => 'timeSinceFirstEvent',
|
142
|
+
:value => '13.15 minutes'
|
143
|
+
}],
|
144
|
+
:percentiles => {
|
145
|
+
:last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
|
146
|
+
}
|
147
|
+
},
|
148
|
+
:payment_abuse => {
|
149
|
+
:score => 0.28610507028376797,
|
150
|
+
:reasons => [{
|
151
|
+
:name => 'Latest item currency code',
|
152
|
+
:value => 'USD'
|
153
|
+
}, {
|
154
|
+
:name => 'Latest item item ID',
|
155
|
+
:value => 'B004834GQO'
|
156
|
+
}, {
|
157
|
+
:name => 'Latest item product title',
|
158
|
+
:value => 'The Slanket Blanket-Texas Tea'
|
159
|
+
}],
|
160
|
+
:percentiles => {
|
161
|
+
:last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
|
162
|
+
}
|
163
|
+
},
|
164
|
+
:promotion_abuse => {
|
165
|
+
:score => 0.05731508921450917,
|
166
|
+
:percentiles => {
|
167
|
+
:last_7_days => -1.0, :last_1_days => -1.0, :last_10_days => -1.0, :last_5_days => -1.0
|
168
|
+
}
|
169
|
+
}
|
170
|
+
},
|
171
|
+
:status => 0,
|
172
|
+
:error_message => 'OK'
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
113
176
|
def fully_qualified_api_endpoint
|
114
177
|
Sift::Client::API_ENDPOINT + Sift.rest_api_path
|
115
178
|
end
|
@@ -554,4 +617,106 @@ describe Sift::Client do
|
|
554
617
|
expect(response.body["decisions"]["content_abuse"]["decision"]["id"]).to eq("decision7")
|
555
618
|
end
|
556
619
|
|
620
|
+
it "Successfully submits a v205 event with SCORE_PERCENTILES" do
|
621
|
+
response_json =
|
622
|
+
{ :status => 0, :error_message => "OK", :score_response => percentile_response_json}
|
623
|
+
stub_request(:post, "https://api.siftscience.com/v205/events?fields=SCORE_PERCENTILES&return_score=true").
|
624
|
+
with { | request|
|
625
|
+
parsed_body = JSON.parse(request.body)
|
626
|
+
expect(parsed_body).to include("$api_key" => "overridden")
|
627
|
+
}.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
|
628
|
+
|
629
|
+
api_key = "foobar"
|
630
|
+
event = "$transaction"
|
631
|
+
properties = valid_transaction_properties
|
632
|
+
|
633
|
+
response = Sift::Client.new(:api_key => api_key, :version => "205")
|
634
|
+
.track(event, properties, :api_key => "overridden", :include_score_percentiles => "true", :return_score => "true")
|
635
|
+
expect(response.ok?).to eq(true)
|
636
|
+
expect(response.api_status).to eq(0)
|
637
|
+
expect(response.api_error_message).to eq("OK")
|
638
|
+
expect(response.body["score_response"]["scores"]["account_abuse"]["percentiles"]["last_7_days"]).to eq(-1.0)
|
639
|
+
end
|
640
|
+
|
641
|
+
it "Successfully submits a v205 event with SCORE_PERCENTILES" do
|
642
|
+
response_json =
|
643
|
+
{ :status => 0, :error_message => "OK", :score_response => percentile_response_json}
|
644
|
+
stub_request(:post, "https://api.siftscience.com/v205/events?fields=SCORE_PERCENTILES&return_score=true").
|
645
|
+
with { | request|
|
646
|
+
parsed_body = JSON.parse(request.body)
|
647
|
+
expect(parsed_body).to include("$api_key" => "overridden")
|
648
|
+
}.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
|
649
|
+
|
650
|
+
api_key = "foobar"
|
651
|
+
event = "$transaction"
|
652
|
+
properties = valid_transaction_properties
|
653
|
+
|
654
|
+
response = Sift::Client.new(:api_key => api_key, :version => "205")
|
655
|
+
.track(event, properties, :api_key => "overridden", :include_score_percentiles => "true", :return_score => "true")
|
656
|
+
expect(response.ok?).to eq(true)
|
657
|
+
expect(response.api_status).to eq(0)
|
658
|
+
expect(response.api_error_message).to eq("OK")
|
659
|
+
expect(response.body["score_response"]["scores"]["account_abuse"]["percentiles"]["last_7_days"]).to eq(-1.0)
|
660
|
+
end
|
661
|
+
|
662
|
+
it "Successfully fetches a v205 score with SCORE_PERCENTILES" do
|
663
|
+
|
664
|
+
api_key = "foobar"
|
665
|
+
response_json = score_response_json
|
666
|
+
|
667
|
+
stub_request(:get, "https://api.siftscience.com/v205/score/247019/?api_key=foobar&fields=SCORE_PERCENTILES")
|
668
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json),
|
669
|
+
:headers => {"content-type"=>"application/json; charset=UTF-8",
|
670
|
+
"content-length"=> "74"})
|
671
|
+
|
672
|
+
response = Sift::Client.new(:api_key => api_key)
|
673
|
+
.score(score_response_json[:user_id], :version => 205, :include_score_percentiles => "true")
|
674
|
+
expect(response.ok?).to eq(true)
|
675
|
+
expect(response.api_status).to eq(0)
|
676
|
+
expect(response.api_error_message).to eq("OK")
|
677
|
+
|
678
|
+
expect(response.body["score"]).to eq(0.93)
|
679
|
+
end
|
680
|
+
|
681
|
+
it "Successfully executes client.get_user_score() with SCORE_PERCENTILES" do
|
682
|
+
|
683
|
+
api_key = "foobar"
|
684
|
+
response_json = user_score_response_json
|
685
|
+
|
686
|
+
stub_request(:get, "https://api.siftscience.com/v205/users/247019/score?api_key=foobar&fields=SCORE_PERCENTILES")
|
687
|
+
.to_return(:status => 200, :body => MultiJson.dump(response_json),
|
688
|
+
:headers => {"content-type"=>"application/json; charset=UTF-8",
|
689
|
+
"content-length"=> "74"})
|
690
|
+
|
691
|
+
response = Sift::Client.new(:api_key => api_key)
|
692
|
+
.get_user_score(user_score_response_json[:entity_id], :include_score_percentiles => "true")
|
693
|
+
expect(response.ok?).to eq(true)
|
694
|
+
expect(response.api_status).to eq(0)
|
695
|
+
expect(response.api_error_message).to eq("OK")
|
696
|
+
|
697
|
+
expect(response.body["entity_id"]).to eq("247019")
|
698
|
+
expect(response.body["scores"]["payment_abuse"]["score"]).to eq(0.78)
|
699
|
+
end
|
700
|
+
|
701
|
+
it "Successfully submits a v205 event with WARNINGS" do
|
702
|
+
response_json =
|
703
|
+
{ :status => 0, :error_message => "OK", :warnings => warnings}
|
704
|
+
stub_request(:post, "https://api.siftscience.com/v205/events?fields=WARNINGS").
|
705
|
+
with { | request|
|
706
|
+
parsed_body = JSON.parse(request.body)
|
707
|
+
expect(parsed_body).to include("$api_key" => "overridden")
|
708
|
+
}.to_return(:status => 200, :body => MultiJson.dump(response_json), :headers => {})
|
709
|
+
|
710
|
+
api_key = "foobar"
|
711
|
+
event = "$transaction"
|
712
|
+
properties = valid_transaction_properties
|
713
|
+
|
714
|
+
response = Sift::Client.new(:api_key => api_key, :version => "205")
|
715
|
+
.track(event, properties, :api_key => "overridden",:warnings => "true")
|
716
|
+
expect(response.ok?).to eq(true)
|
717
|
+
expect(response.api_status).to eq(0)
|
718
|
+
expect(response.api_error_message).to eq("OK")
|
719
|
+
expect(response.body["warnings"]["count"]).to eq(1)
|
720
|
+
expect(response.body["warnings"]["items"][0]["message"]).to eq("Invalid currency")
|
721
|
+
end
|
557
722
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "sift"
|
2
|
+
|
3
|
+
class DecisionAPI
|
4
|
+
|
5
|
+
@@client = Sift::Client.new(:api_key => ENV["API_KEY"], :account_id => ENV["ACCOUNT_ID"])
|
6
|
+
|
7
|
+
def apply_user_decision()
|
8
|
+
properties = {
|
9
|
+
"decision_id": "integration_app_watch_account_abuse",
|
10
|
+
"description": "User linked to three other payment abusers and ordering high value items",
|
11
|
+
"source": "manual_review",
|
12
|
+
"analyst": "analyst@example.com",
|
13
|
+
"user_id": "userId"
|
14
|
+
}
|
15
|
+
|
16
|
+
return @@client.apply_decision(properties)
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_order_decision()
|
20
|
+
properties = {
|
21
|
+
"decision_id": "block_order_payment_abuse",
|
22
|
+
"description": "applied via the high priority queue, queued user because their risk score exceeded 85",
|
23
|
+
"source": "AUTOMATED_RULE",
|
24
|
+
"user_id": "userId",
|
25
|
+
"order_id": "orderId"
|
26
|
+
}
|
27
|
+
|
28
|
+
return @@client.apply_decision(properties)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|