Assessing Risk in FrankieOne

This guide provides a comprehensive overview of how to implement and configure the Risk-Based Onboarding Engine in FrankieOne v2.0.0. It covers the core concepts of risk calculation, workflow integration, and the detailed configuration of risk factors.

How Risk Works in Workflows

The FrankieOne v2 Risk Engine transforms static, check-based verification into a dynamic, intelligence-driven framework. This enables you to design sophisticated, risk-based user journeys where the level of due diligence is directly proportional to the calculated risk of an entity.

Core Concepts

The subject of the risk assessment, which can be an INDIVIDUAL or an ORGANIZATION.

A container for a specific customer context (e.g., KYC Onboarding). Each service profile is assigned one and only one risk profile.

The central JSON configuration that governs all risk calculations. It defines the risk levels (e.g., LOW, MEDIUM, HIGH) and the factors to be evaluated.

A specific rule that extracts data, applies scoring logic, and produces a numerical score. Each factor is an independent unit of risk logic.

The final output of a risk evaluation generated at the end of a workflow. It contains the aggregated score, the corresponding risk level, and a detailed list of all contributing factors.

The Risk Assessment Lifecycle

Risk is assessed in a multi-stage process integrated directly into the workflow execution.

1

Workflow Start

The system loads all VALID risk factors already associated with the entity’s service profile into the workflow’s context. The initial risk score is based on this pre-existing state.

2

Data Collection Steps

As the workflow progresses, steps like AML, IDV, and Onboarding Fraud checks generate processResults, which serve as the source data for many risk factors.

3

Risk Calculation

A dedicated RISK step is triggered. This step evaluates all factors defined in the risk profile, applies the configured scoring logic (scoreMethod), and aggregates the results to produce a final score for each factor.

4

Workflow Finish

The scores from all evaluated risk factors are summed to produce the final workflowRiskScore. This score is then mapped to a workflowRiskLevel. The complete RiskAssessment is added to the workflowResult.

5

Persistence

The new risk assessment is persisted. Any previous factors whose underlying data has changed are marked as STALE.

Risk Factor Statuses

Each risk factor has a status to manage its lifecycle and ensure calculation accuracy:

StatusDescription
VALIDThe default status. The factor is current and contributes to the risk score.
STALEThe underlying data used to generate the factor has changed (e.g., an entity’s address was updated). Stale factors are excluded from future calculations and are replaced by new, VALID factors.
OVERRIDDENA user has manually overridden the factor’s score. The manualOverrideScore will be used instead of the system-calculated score.
DISCARDEDThe factor was generated during a workflow but later deemed irrelevant within the same execution. It is excluded from the final risk assessment.

Risk Profile Configuration

The entire risk engine is driven by the risk_profiles.json configuration file. Each profile defines the levels and factors for risk calculation.

levels Schema

The levels array defines the qualitative risk bands and their corresponding numerical score ranges.

1"levels": [
2 {
3 "label": "LOW",
4 "range": { "min": 0, "max": 40 }
5 },
6 {
7 "label": "MEDIUM",
8 "range": { "min": 41, "max": 70 }
9 },
10 {
11 "label": "HIGH",
12 "range": { "min": 71, "max": 90 },
13 "extra": {
14 "GenerateIssue": {
15 "category": "RISK",
16 "issue": "RISK_THRESHOLD_HIGH",
17 "severity": "REVIEW"
18 }
19 }
20 },
21 {
22 "label": "UNACCEPTABLE",
23 "range": { "min": 91 },
24 "extra": {
25 "GenerateIssue": {
26 "category": "RISK",
27 "issue": "RISK_THRESHOLD_UNACCEPTABLE",
28 "severity": "BLOCK"
29 }
30 }
31 }
32]
  • label: The name of the risk level (e.g., LOW, HIGH).
  • range: Defines the numerical score boundaries. min and max are inclusive.
  • extra.GenerateIssue: An optional object that instructs the engine to generate a workflow issue when the risk level is reached.

factors Schema

The factors array lists all risk factors to be evaluated. Each factor object is a rule for calculating a specific risk score component.

1{
2 "name": "fraud_email",
3 "description": "Fraud Email Signal",
4 "default": "LOW",
5 "scoreMethod": "lookup",
6 "aggregate": "max",
7 "defaultScore": {
8 "name": "default",
9 "score": 0,
10 "value": "LOW",
11 "flags": ["include_zero"]
12 },
13 "scores": [
14 { "value": "LOW", "score": 0, "flags": ["include_zero"] },
15 { "value": "MEDIUM", "score": 10 },
16 { "value": "HIGH", "score": 20 },
17 { "value": "UNACCEPTABLE", "score": 30 },
18 { "value": "UNKNOWN", "score": 40 }
19 ]
20}
  • name: The unique identifier for the risk factor (e.g., fraud_email).
  • description: A human-readable description for display and auditing.
  • handler: The name of the internal service responsible for data extraction and scoring logic (e.g., jurisdiction_lookup).
  • scoreMethod: The method for assigning a score (lookup, lookup_range, bool).
  • aggregate: The method for aggregating multiple scores into a single factor score (sum, max, min, average, count). This applies only when a handler returns multiple values.
  • scores: An array of objects defining the value-to-score mapping.
  • defaultScore: A fallback score to apply if the input data cannot be mapped via the scores array.

Risk Factor Library

This section provides a comprehensive catalogue of the risk factors available in the FrankieOne platform. Each factor is designed to assess a specific element of risk during the onboarding process.

KYC Risk Factors (Individuals)

These factors are applicable to INDIVIDUAL entities and focus on identity attributes, jurisdiction, and AML signals.

Calculates risk based on the individual’s age at the time of workflow execution.

  • Handler: entity_age
  • Score Method: lookup_range
  • Data Source: individual.dateOfBirth.normalized
Example Configuration:
1{
2 "name": "entity_age",
3 "description": "Calculates risk based on the entity's age.",
4 "handler": "entity_age",
5 "scoreMethod": "lookup_range",
6 "scores": [
7 { "name": "Minor", "range": { "max": 17 }, "score": 100 },
8 { "name": "Young Adult", "range": { "min": 18, "max": 25 }, "score": 15 },
9 { "name": "Standard Adult", "range": { "min": 26 }, "score": 0 }
10 ],
11 "defaultScore": { "value": "N/A", "score": 80 }
12}

Applies risk based on the type(s) of identity documents provided. It aggregates scores if multiple documents are present.

  • Handler: document_type_lookup
  • Score Method: lookup
  • Aggregate Method: max (Typically used to take the score of the riskiest document)
  • Data Source: individual.documents.IDENTITY[].type
Example Configuration:
1{
2 "name": "document_type",
3 "description": "Scores risk based on the provided document type.",
4 "handler": "document_type_lookup",
5 "scoreMethod": "lookup",
6 "aggregate": "max",
7 "scores": [
8 { "value": "PASSPORT", "score": 5 },
9 { "value": "DRIVERS_LICENSE", "score": 10 },
10 { "value": "UTILITY_BILL", "score": 40 }
11 ],
12 "defaultScore": { "value": "No Documents", "score": 0 }
13}

Scores risk based on the provided nationality.

  • Handler: jurisdiction_lookup
  • Score Method: lookup
  • Aggregate Method: max
  • Data Source: individual.nationality
Example Configuration:
1{
2 "name": "nationality_risk",
3 "description": "Scores risk based on the provided nationality.",
4 "handler": "jurisdiction_lookup",
5 "config": { "source": "nationality" },
6 "scoreMethod": "lookup",
7 "aggregate": "max",
8 "scores": [
9 { "value": "IRN", "score": 100 },
10 { "value": "RUS", "score": 50 },
11 { "value": "AUS", "score": 0 }
12 ],
13 "defaultScore": { "value": "Other", "score": 30 }
14}

Scores risk based on the current residential address country.

  • Handler: jurisdiction_lookup
  • Score Method: lookup
  • Aggregate Method: max
  • Data Source: individual.addresses[] where type is RESIDENTIAL
Example Configuration:
1{
2 "name": "residential_country_risk",
3 "description": "Risk based on the current residential address country.",
4 "handler": "jurisdiction_lookup",
5 "config": { "source": "address", "addressType": "RESIDENTIAL" },
6 "scoreMethod": "lookup",
7 "aggregate": "max",
8 "scores": [
9 { "value": "NGA", "score": 70 },
10 { "value": "AUS", "score": 5 }
11 ],
12 "defaultScore": { "value": "Other", "score": 30 }
13}

These boolean factors check for the presence of corresponding data in AML processResults.

  • Handlers: is_pep, has_sanctions, has_adverse_media, on_watchlist
  • Score Method: bool
  • Data Source: processResults[] where supplementaryData.type is AML
Example Configuration (for is_pep):
1{
2 "name": "is_pep",
3 "description": "Entity Has PEP Hits",
4 "handler": "is_pep",
5 "scoreMethod": "bool",
6 "scores": [
7 { "value": true, "score": 50 }
8 ]
9}

Scores risk based on the numerical PEP classification level (1-4).

  • Handler: pep_level_lookup
  • Score Method: lookup
  • Aggregate Method: max
  • Data Source: processResults[].supplementaryData.pepData[].level
Example Configuration:
1{
2 "name": "pep_level",
3 "description": "Risk based on the PEP classification level",
4 "handler": "pep_level_lookup",
5 "scoreMethod": "lookup",
6 "aggregate": "max",
7 "scores": [
8 { "value": "1", "score": 100 },
9 { "value": "2", "score": 80 },
10 { "value": "3", "score": 50 },
11 { "value": "4", "score": 30 }
12 ],
13 "defaultScore": { "value": "N/A", "score": 0 }
14}

Scores risk based on the number of times an entity has executed a specific workflow.

  • Handler: workflow_attempts_counter
  • Score Method: lookup_range
  • Data Source: Historical workflow execution records for the entity.
Example Configuration:
1{
2 "name": "workflow_attempts",
3 "description": "Total onboarding attempts for this workflow.",
4 "handler": "workflow_attempts_counter",
5 "scoreMethod": "lookup_range",
6 "scores": [
7 { "name": "First Attempt", "range": { "max": 1 }, "score": 0 },
8 { "name": "Multiple Attempts", "range": { "min": 2, "max": 3 }, "score": 30 },
9 { "name": "High Attempts", "range": { "min": 4 }, "score": 70 }
10 ]
11}

Scores risk based on custom key-value data provided by the client in the individual.customAttributes object.

  • Handler: custom_attribute_lookup
  • Score Method: lookup
  • Data Source: individual.customAttributes
Example Configuration:
1{
2 "name": "product_type_risk",
3 "description": "Scores risk based on the client-provided 'product_type' attribute.",
4 "handler": "custom_attribute_lookup",
5 "config": {
6 "attributeName": "product_type"
7 },
8 "scoreMethod": "lookup",
9 "scores": [
10 { "value": "Card Present", "score": 5 },
11 { "value": "Online Payments", "score": 20 }
12 ],
13 "defaultScore": { "value": "Other", "score": 10 }
14}

Scores risk based on the number of potential duplicate profiles for the entity that have not yet been resolved.

  • Handler: unresolved_duplicates
  • Score Method: lookup_range
  • Data Source: Duplicate check process results.
Example Configuration:
1{
2 "name": "unresolved_duplicates",
3 "description": "Unresolved duplicates",
4 "handler": "unresolved_duplicates",
5 "scoreMethod": "lookup_range",
6 "scores": [
7 {
8 "name": "Any unresolved duplicates",
9 "range": { "min": 1 },
10 "score": 20
11 }
12 ]
13}

Scores risk based on the number of duplicate profiles that have been confirmed as TRUE_POSITIVE.

  • Handler: true_positive_duplicates
  • Score Method: lookup_range
  • Data Source: Duplicate check process results.
Example Configuration:
1{
2 "name": "true_positive_duplicates",
3 "description": "Resolved duplicates",
4 "handler": "true_positive_duplicates",
5 "scoreMethod": "lookup_range",
6 "scores": [
7 {
8 "name": "Any resolved duplicates",
9 "range": { "min": 1 },
10 "score": 2
11 }
12 ]
13}

Onboarding Fraud Risk Factors

This section details the risk factors derived from Onboarding Fraud checks. These checks provide signals for device, IP address, phone number, and email address risk.

This factor scores risk based on the number of sessions used during an onboarding workflow. An excessive number of sessions can indicate suspicious behavior.

  • Handler: fraud_count_session
  • Score Method: lookup_range
  • Returns: A single integer value representing the session count.
Example Configuration:
1{
2 "name": "fraud_count_session",
3 "description": "Fraud Session Count",
4 "scoreMethod": "lookup",
5 "defaultScore": {
6 "name": "Default",
7 "value": "0",
8 "score": 0,
9 "flags": ["include_zero"]
10 },
11 "scores": [
12 {
13 "name": "Up to 2",
14 "range": { "max": 2 },
15 "score": 0
16 },
17 {
18 "name": "Between 3-5",
19 "range": { "min": 3, "max": 5 },
20 "score": 10
21 },
22 {
23 "name": "Greater than 5",
24 "range": { "min": 6 },
25 "score": 20
26 }
27 ]
28}

This factor aggregates risk signals from IP address checks across one or more sessions.

  • Handler: fraud_ip_address
  • Score Method: lookup
  • Aggregate: max (to capture the highest risk signal from any session)
  • Returns: An array of risk levels (e.g., [“HIGH”, “LOW”]).
Example Configuration:
1{
2 "name": "fraud_ip_address",
3 "description": "Fraud IP Signal",
4 "aggregate": "max",
5 "defaultScore": {
6 "name": "default",
7 "value": "LOW",
8 "score": 0,
9 "flags": ["include_zero"]
10 },
11 "scores": [
12 { "value": "LOW", "score": 0, "flags": ["include_zero"]},
13 { "value": "MEDIUM", "score": 10 },
14 { "value": "HIGH", "score": 20 },
15 { "value": "UNACCEPTABLE", "score": 30 },
16 { "value": "UNKNOWN", "score": 40 }
17 ]
18}

This factor aggregates risk signals from device checks across one or more sessions.

  • Handler: fraud_device
  • Score Method: lookup
  • Aggregate: max (to capture the highest risk signal from any device)
  • Returns: An array of risk levels (e.g., [“HIGH”, “LOW”]).
Example Configuration:
1{
2 "name": "fraud_device",
3 "description": "Fraud Device Signal",
4 "aggregate": "max",
5 "defaultScore": {
6 "name": "default",
7 "score": 0,
8 "value": "LOW",
9 "flags": ["include_zero"]
10 },
11 "scores": [
12 { "value": "LOW", "score": 0, "flags": ["include_zero"] },
13 { "value": "MEDIUM", "score": 10 },
14 { "value": "HIGH", "score": 20 },
15 { "value": "UNACCEPTABLE", "score": 30 },
16 { "value": "UNKNOWN", "score": 40 }
17 ]
18}

This factor scores risk based on the fraud signal for the selected entity email address.

  • Handler: fraud_email
  • Score Method: lookup
  • Returns: A single risk level value (e.g., “MEDIUM”).
Example Configuration:
1{
2 "name": "fraud_email",
3 "description": "Fraud Email Signal",
4 "defaultScore": {
5 "name": "default",
6 "score": 0,
7 "value": "LOW",
8 "flags": ["include_zero"]
9 },
10 "scores": [
11 { "value": "LOW", "score": 0, "flags": ["include_zero"] },
12 { "value": "MEDIUM", "score": 10 },
13 { "value": "HIGH", "score": 20 },
14 { "value": "UNACCEPTABLE", "score": 30 },
15 { "value": "UNKNOWN", "score": 40 }
16 ]
17}

This factor scores risk based on the fraud signal for the selected entity phone number.

  • Handler: fraud_phone_number
  • Score Method: lookup
  • Returns: A single risk level value (e.g., “HIGH”).
Example Configuration:
1{
2 "name": "fraud_phone_number",
3 "description": "Fraud Phone Signal",
4 "defaultScore": {
5 "name": "default",
6 "score": 0,
7 "value": "LOW",
8 "flags": ["include_zero"]
9 },
10 "scores": [
11 { "value": "LOW", "score": 0, "flags": ["include_zero"] },
12 { "value": "MEDIUM", "score": 10 },
13 { "value": "HIGH", "score": 20 },
14 { "value": "UNACCEPTABLE", "score": 30 },
15 { "value": "UNKNOWN", "score": 40 }
16 ]
17}

Risk in Workflows: The Fraud Step

The Onboarding Fraud solution is integrated into workflows via a dedicated Fraud Step.

Step Results

The Fraud Step can return one of three results:

ResultDescription
CLEARAll underlying checks passed without raising any concerns. No operator action is required.
HITOne or more underlying checks returned results that should be reviewed by an operator.
UNCHECKEDThe step was unable to generate any results, likely due to a data validation or system issue.

Impact of Resolving Results on Risk Calculation

When an operator resolves a HIT, their action directly impacts how risk is calculated on subsequent workflow runs.

Operator Action/StatusEffect on Risk Calculation
No manualStatus (Unresolved)The risk from the provider is used as is.
FALSE_POSITIVEThe risk for the result is ignored entirely and excluded from the calculation.
TRUE_POSITIVE_ACCEPTThe risk for the result is forced to LOW to reflect that the signal is real but the risk has been accepted by the operator.
TRUE_POSITIVE_REJECTThe risk for the result remains as it was from the provider, reflecting that the signal is real and has been rejected by the operator.

Advanced Configuration

Aggregation Methods

Aggregation applies only when a factor’s handler yields multiple input values (e.g., multiple device risk scores). The engine first calculates an “item score” for each value and then collapses them into a single “factor score” using one of the following methods:

MethodDescription
maxThe final factor score is the highest score from all evaluated items.
sumThe final factor score is the sum of all item scores.
minThe final factor score is the lowest score from all evaluated items.
averageThe final factor score is the mathematical average of all item scores.
countThe final score is determined by the total number of input items, which is then mapped against the ranges defined in the scores array.

Connector-Level HIT/CLEAR Mapping

For some third-party providers, you can configure how their risk levels map to FrankieOne’s HIT or CLEAR results at the connector level. This allows for fine-tuning of your risk appetite.

By default, the mapping is:

  • HIGH, MEDIUM, UNACCEPTABLE -> HIT
  • LOW -> CLEAR

You can override this behavior in the connector configuration. For example, to treat MEDIUM risk as CLEAR:

1"connector": {
2 "provider": {
3 "...rest of provider config": "",
4 "v2": {
5 "riskLevelPROResultMapping": {
6 "FRAUD_DEVICE": {
7 "MEDIUM": "CLEAR"
8 },
9 "FRAUD_IP_ADDRESS": {
10 "MEDIUM": "CLEAR"
11 },
12 "FRAUD_EMAIL_ADDRESS": {
13 "MEDIUM": "CLEAR"
14 },
15 "FRAUD_PHONE_NUMBER": {
16 "MEDIUM": "CLEAR"
17 }
18 }
19 },
20 "...rest of provider config": ""
21 }
22}