Skip to content

Commit 99ed40d

Browse files
committed
Add support for risk score reasons
1 parent df26ea7 commit 99ed40d

File tree

8 files changed

+95
-7
lines changed

8 files changed

+95
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* **Breaking** Updated `TransactionReport` to make the `ipAddress` parameter
88
optional. Now the `tag` and at least one of the following paramters must be
99
supplied: `ipAddress`, `maxmindId`, `minfraudId`, `transactionId`.
10+
* Added support for the new risk reasons outputs in minFraud Factors.
1011

1112
6.1.0 (2024-04-16)
1213
------------------

e2e/js/package-lock.json

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e/ts/package-lock.json

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fixtures/reasons.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[
2+
{
3+
"multiplier": 45,
4+
"reasons": [
5+
{
6+
"code": "ANONYMOUS_IP",
7+
"reason": "Risk due to IP being an Anonymous IP"
8+
}
9+
]
10+
},
11+
{
12+
"multiplier": 1.8,
13+
"reasons": [
14+
{
15+
"code": "TIME_OF_DAY",
16+
"reason": "Risk due to local time of day"
17+
}
18+
]
19+
},
20+
{
21+
"multiplier": 1.6,
22+
"reasons": [
23+
{
24+
"reason": "Riskiness of newly-sighted email domain",
25+
"code": "EMAIL_DOMAIN_NEW"
26+
}
27+
]
28+
},
29+
{
30+
"multiplier": 0.34,
31+
"reasons": [
32+
{
33+
"code": "EMAIL_ADDRESS_NEW",
34+
"reason": "Riskiness of newly-sighted email address"
35+
}
36+
]
37+
}
38+
]

src/response/models/factors.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import * as webRecords from '../web-records';
44
import Insights from './insights';
55

66
export default class Factors extends Insights {
7+
public readonly riskScoreReasons?: records.RiskScoreReason[];
8+
79
/**
810
* An object containing GeoIP2 and minFraud Insights information about the IP
911
* address.
@@ -13,6 +15,7 @@ export default class Factors extends Insights {
1315
public constructor(response: webRecords.FactorsResponse) {
1416
super(response);
1517

18+
this.riskScoreReasons = response.risk_score_reasons;
1619
this.subscores = camelizeResponse(response.subscores) as records.Subscores;
1720
}
1821
}

src/response/records.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,35 @@ export interface Disposition {
330330
readonly ruleLabel?: string;
331331
}
332332

333+
/**
334+
* This object describes one of the reasons for the multiplier.
335+
*/
336+
export interface Reason {
337+
/**
338+
* The machine-readable code for the reason.
339+
*/
340+
code: string;
341+
/**
342+
* The human-readable description of the reason.
343+
*/
344+
reason: string;
345+
}
346+
347+
/**
348+
* The object describing the risk score multiplier and the reasons for that
349+
* multiplier.
350+
*/
351+
export interface RiskScoreReason {
352+
/**
353+
* The risk score multiplier.
354+
*/
355+
multiplier: number;
356+
/**
357+
* The reasons for the multiplier.
358+
*/
359+
reasons: Reason[];
360+
}
361+
333362
/**
334363
* This object contains scores for many of the individual risk factors that
335364
* are used to calculate the overall risk score.

src/response/web-records.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ export interface DispositionWebRecord {
114114
readonly rule_label?: string;
115115
}
116116

117+
export interface ReasonWebRecord {
118+
code: string;
119+
reason: string;
120+
}
121+
122+
export interface RiskScoreReasonWebRecord {
123+
multiplier: number;
124+
reasons: ReasonWebRecord[];
125+
}
126+
117127
export interface SubscoresWebRecord {
118128
readonly avs_result?: number;
119129
readonly billing_address?: number;
@@ -163,5 +173,6 @@ export interface InsightsResponse extends ScoreResponse {
163173
}
164174

165175
export interface FactorsResponse extends InsightsResponse {
176+
readonly risk_score_reasons?: RiskScoreReasonWebRecord[];
166177
readonly subscores: SubscoresWebRecord;
167178
}

src/webServiceClient.spec.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import cloneDeep = require('lodash.clonedeep');
22
import nock from 'nock';
33
import * as models from './response/models';
44
import * as insights from '../fixtures/insights.json';
5+
import reasons from '../fixtures/reasons.json';
56
import * as score from '../fixtures/score.json';
67
import * as subscores from '../fixtures/subscores.json';
78
import {
@@ -26,6 +27,7 @@ const client = new Client(auth.user, auth.pass);
2627
describe('WebServiceClient', () => {
2728
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2829
const factors = cloneDeep(insights) as any;
30+
factors.response.full.risk_score_reasons = cloneDeep(reasons);
2931
factors.response.full.subscores = cloneDeep(subscores);
3032

3133
describe('factors()', () => {
@@ -36,7 +38,7 @@ describe('WebServiceClient', () => {
3638
});
3739

3840
it('handles "full" responses', async () => {
39-
expect.assertions(159);
41+
expect.assertions(164);
4042

4143
nockInstance
4244
.post(fullPath('factors'), factors.request.basic)
@@ -239,6 +241,14 @@ describe('WebServiceClient', () => {
239241
);
240242
expect(got.warnings?.[0].inputPointer).toEqual('/shipping/city');
241243

244+
expect(got.riskScoreReasons).toHaveLength(4);
245+
expect(got.riskScoreReasons?.[0].multiplier).toEqual(45);
246+
expect(got.riskScoreReasons?.[0].reasons).toHaveLength(1);
247+
expect(got.riskScoreReasons?.[0].reasons[0].code).toEqual('ANONYMOUS_IP');
248+
expect(got.riskScoreReasons?.[0].reasons[0].reason).toEqual(
249+
'Risk due to IP being an Anonymous IP'
250+
);
251+
242252
expect(got?.subscores?.avsResult).toEqual(0.01);
243253
expect(got?.subscores?.billingAddress).toEqual(0.02);
244254
expect(got?.subscores?.billingAddressDistanceToIpLocation).toEqual(0.03);

0 commit comments

Comments
 (0)