Get started with the Quickstart

A quick introduction to building with FrankieOne.

The most important concept in FrankieOne is an Entity. An entity represents a person or business being verified. Typically, an entity is verified as soon as it is created in FrankieOne as part of customer onboarding. You can continue to perform identity and fraud checks during the entity's lifecycle as part of your ongoing monitoring program.

In this tutorial you will write code to create and verify an entity. Then update the entity's details in order to test a failed verification scenario.

Make your first API call

You authenticate to the FrankieOne API using an API Key. Contact FrankieOne to obtain your API key to the Demo environment.

You will also be assigned a Customer ID which identifies your application to FrankieOne.

You must specify your Customer ID and API key in each request you make to FrankieOne using X-Frankie-CustomerID and api_key request headers respectively.

Create an entity in FrankieOne.

  1. In the example below, replace YOUR_CUSTOMER_ID with your Customer ID and YOUR_API_KEY with your API key provided by FrankieOne.
  2. Copy the resulting code into your command line, and run the command
#!/bin/bash

CUSTOMER_ID="YOUR_CUSTOMER_ID"
API_KEY="YOUR_API_KEY"

curl --request POST \
     --url https://api.demo.frankiefinancial.io/compliance/v1.2/entity \
     --header "Accept: application/json" \
     --header "X-Frankie-CustomerID: $CUSTOMER_ID" \
     --header "api_key: $API_KEY" \
     --header "Content-Type: application/json" \
     --data '
{
  "entity": {
    "name": {
        "familyName": "Jeffries",
        "middleName": "J",
        "givenName": "Doug",
        "displayName": "Doug J Jeffries"
    },
    "dateOfBirth": {
        "dateOfBirth": "1974-08-08"
    },
    "gender" : "M",
    "addresses": [
        {
            "addressType": "RESIDENTIAL1",
            "buildingName": "",
            "unitNumber": "",
            "streetNumber": "1200",
            "streetName": "SW Orleans",
            "streetType": "Street",
            "suburb": "",
            "town": "Topeka",
            "region": "",
            "state": "KS",
            "country": "USA",
            "postalCode": "66604",
            "longForm": "1200 SW Orleans Street, Topeka, KS 66604"
        }    
    ],
    "identityDocs": [
        {
            "idType": "NATIONAL_ID",
            "country": "USA",
            "idNumber": "782013349"
        }    
    ]
  }
}'
package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    url := "https://api.demo.frankiefinancial.io/compliance/v1.2/entity"
    customerID := "YOUR_CUSTOMER_ID"
    apiKey := "YOUR_API_KEY"

    var jsonStr = []byte(`{
      "entity": {
        "name": {
            "familyName": "Jeffries",
            "middleName": "J",
            "givenName": "Doug",
            "displayName": "Doug J Jeffries"
        },
        "dateOfBirth": {
            "dateOfBirth": "1974-08-08"
        },
        "gender" : "M",
        "addresses": [
            {
                "addressType": "RESIDENTIAL1",
                "buildingName": "",
                "unitNumber": "",
                "streetNumber": "1200",
                "streetName": "SW Orleans",
                "streetType": "Street",
                "suburb": "",
                "town": "Topeka",
                "region": "",
                "state": "KS",
                "country": "USA",
                "postalCode": "66604",
                "longForm": "1200 SW Orleans Street, Topeka, KS 66604"
            }    
        ],
        "identityDocs": [
            {
                "idType": "NATIONAL_ID",
                "country": "USA",
                "idNumber": "782013349"
            }    
        ]
      }
}`)

    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Accept", "application/json")
    req.Header.Set("X-Frankie-CustomerID", customerID)
    req.Header.Set("api_key", apiKey)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println("response Status:", resp.Status)
    fmt.Println("response Headers:", resp.Header)
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println("response Body:", string(body))
}
const https = require("https");

const customerID = "YOUR_CUSTOMER_ID";
const apiKey = "YOUR_API_KEY";

const payload = JSON.stringify({
  entity: {
    name: {
        familyName: "Jeffries",
        middleName: "J",
        givenName: "Doug",
        displayName: "Doug J Jeffries"
    },
    dateOfBirth: {
        dateOfBirth: "1974-08-08"
    },
    gender : "M",
    addresses: [
        {
            addressType: "RESIDENTIAL1",
            buildingName: "",
            unitNumber: "",
            streetNumber: "1200",
            streetName: "SW Orleans",
            streetType: "Street",
            suburb: "",
            town: "Topeka",
            region: "",
            state: "KS",
            country: "USA",
            postalCode: "66604",
            longForm: "1200 SW Orleans Street, Topeka, KS 66604"
        }    
    ],
    identityDocs: [
        {
            idType: "NATIONAL_ID",
            country: "USA",
            idNumber: "782013349"
        }    
    ]
  }
});

const options = {
  hostname: "api.demo.frankiefinancial.io",
  port: 443,
  path: "/compliance/v1.2/entity",
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Accept: "application/json",
    "X-Frankie-CustomerID": customerID,
    api_key: apiKey,
  },
};

const req = https.request(options, (res) => {
  console.log(`statusCode: ${res.statusCode}`);

  res.on("data", (d) => {
    process.stdout.write(d);
  });
});

req.on("error", (error) => {
  console.error(error);
});

req.write(payload);
req.end();
import requests
import json

url = "https://api.demo.frankiefinancial.io/compliance/v1.2/entity"
customerID = "YOUR_CUSTOMER_ID"
apiKey = "YOUR_API_KEY"


headers = {
    "Content-Type": "application/json; charset=utf-8",
    "Accept": "application/json",
    "X-Frankie-CustomerID": customerID,
    "api_key": apiKey
}

data = {
  "entity": {
    "name": {
        "familyName": "Jeffries",
        "middleName": "J",
        "givenName": "Doug",
        "displayName": "Doug J Jeffries",
    },
    "dateOfBirth": {
        "dateOfBirth": "1974-08-08",
    },
    "gender" : "M",
    "addresses": [
        {
            "addressType": "RESIDENTIAL1",
            "buildingName": "",
            "unitNumber": "",
            "streetNumber": "1200",
            "streetName": "SW Orleans",
            "streetType": "Street",
            "suburb": "",
            "town": "Topeka",
            "region": "",
            "state": "KS",
            "country": "USA",
            "postalCode": "66604",
            "longForm": "1200 SW Orleans Street, Topeka, KS 66604",
        },    
    ],
    "identityDocs": [
        {
            "idType": "NATIONAL_ID",
            "country": "USA",
            "idNumber": "782013349",
        },    
    ],
  },
}

response = requests.post(url, headers=headers, json=data)

print("Status Code", response.status_code)
print("JSON Response ", response.json())

The response will contain the ID of the newly created entity in FrankieOne.

{
    "entity": {
        "entityId": "871f8a04-19f3-b14f-19ae-117845619fc4",
        "entityType": "INDIVIDUAL"
    },
    ...
}

Verify the entity

The next step is to verify the entity's personal information, using FrankieOne. Behind the scenes FrankieOne will try to match the entity's personal information against multiple data sources. The exact data sources to use and the criteria for determining a match will vary based on your business's needs. Your customer success representative will work with you to set up your account's configuration.

To verify an entity you need to specify an entity profile. The example below species the international entity profile, which is available in the Demo environment. The international entity profile verifies the entity by performing the following checks:

  • Blocklist checks
  • Name checks against 1 datasource and date-of-birth or address checks against 1 datasource (One Plus One rule)
  • Politically Exposed Person (PEP) and Adverse Media checks
  • Biometrics checks

Learn more about entity profiles in About entity profiles

Certain datasources also require you to obtain explicit consent from the user before performing a search. You can specify that this consent was obtained as [Key-Value pairs]. Learn more about obtaining consent in About consent.

Verify the entity's details using the Update and Verify API.

  1. In the example below, replace YOUR_CUSTOMER_ID with your Customer ID and YOUR_API_Key with your API key provided by FrankieOne.
  2. Replace ENTITY_ID with the ID of the entity obtained from the previous step.
  3. Copy the resulting code into your command line, and run the command.
curl https://api.demo.frankiefinancial.io/compliance/v1.2/entity/{ENTITY_ID}/verify/profile/simple \
  -X POST \
  -d '
{
  "entity": {
    "entityId": "871f8a04-19f3-b14f-19ae-117845619fc4",
    "entityProfile": "international",
    "extraData" : [
        {
            "kvpKey": "consent.general",
            "kvpValue": "true",
            "kvpType": "general.bool"
        },
        {
            "kvpKey": "consent.docs",
            "kvpValue": "true",
            "kvpType": "general.bool"
        },
        {
            "kvpKey": "consent.creditheader",
            "kvpValue": "true",
            "kvpType": "general.bool"
        }
    ]
  }
}

💡

Tip: Create and verify in one step

You can create and verify an entity using a single API call by specifying new in the URL path instead of an entity ID. Make sure to store the returned entity ID in your system.

📘

Get up and running quickly with these examples

See the examples here: https://github.com/FrankieFinancial/apiexamples

Inspect verification results

The Verify Entity API response will contain the verification results, which will look like the example below:

{
    "entityProfileResult": {
        "checkId": "b134067f-2d0b-b3f0-23c8-a0c9af803ef6",
        "entityId": "871f8a04-19f3-b14f-19ae-117845619fc4",
        "checkType": "blacklist,one_plus,idvalidate,pep",
        "latestCheckDate": "2022-06-30T07:09:19.975Z",
        "policyName": "default",
        "profileName": "international",
        "riskLevel": "MEDIUM",
        "riskPolicy": "CDD",
        "actionRecommended": "FAIL",
        "checkResults": [
            {
                "checkClass": "fraud",
                "checkType": "blacklist",
                "name": "Blacklist",
                "result": "PASS"
            },
            {
                "checkClass": "kyc",
                "checkType": "one_plus",
                "name": "1+1",
                "result": "PASS"
            },
            {
                "checkClass": "none",
                "checkType": "idvalidate",
                "code": "MISSING_PREREQUISITE",
                "message": "Attestation check failed. The required documents are not present",
                "name": "IDV",
                "result": "FAIL"
            },
            {
                "checkClass": "aml",
                "checkType": "pep",
                "code": "BLOCKED_BY_OTHER_FAIL",
                "message": "Cannot check while there are failed biometric checks",
                "name": "PEP/Sanctions",
                "result": "UNCHECKED"
            }
        ],
        "issueList": [
            "ATT-NCMP"
        ]
    },
    "requestId": "01G6SQ2P2NTBX7GPQVBDKPXTXF",
    ...
}

The results describe what information was checked, the results of those checks, and the risk level FrankieOne assigned to the entity based on those check results. You can also inspect the entityProfileResult.actionRecommended field to inform your system on how to proceed. In this example FrankieOne has recommended that you fail onboarding.

The entityProfileResult.checkResults field describes the check results obtained from verifying this entity. In this case:

  1. The entity was not flagged by your internal Blocklist.
  2. The entity's details were successfully verified according to a One Plus One rule.
  3. Biometricsd (ID validation) failed as an attestation document was not provided by a biometrics provider.
  4. Becuase biometrics failed, FrankieOne did not proceed with AML checks against PEP and sanction lists.

The results described above represent a summary of all check results. The response also contains more details, which you can learn about here.

Full response:
  {
    "checkRisk": {
        "checkDate": "2022-06-30T07:09:20.026Z",
        "checkId": "b134067f-2d0b-b3f0-23c8-a0c9af803ef6",
        "checkPerformedBy": "builtin-risk",
        "checkSource": "various",
        "checkType": "blacklist,one_plus,idvalidate,pep",
        "resultNotes": [
            {
                "kvpKey": "risk_factor.num_pep.value",
                "kvpType": "general.string",
                "kvpValue": "No Match"
            },
            {
                "kvpKey": "risk_factor.num_pep.score",
                "kvpType": "general.integer",
                "kvpValue": "10"
            },
            {
                "kvpKey": "risk_factor.num_pep.description",
                "kvpType": "general.string",
                "kvpValue": "PEP Status"
            },
            {
                "kvpKey": "risk_factor.num_sanctions.value",
                "kvpType": "general.string",
                "kvpValue": "No match"
            },
            {
                "kvpKey": "risk_factor.num_sanctions.score",
                "kvpType": "general.integer",
                "kvpValue": "10"
            },
            {
                "kvpKey": "risk_factor.num_sanctions.description",
                "kvpType": "general.string",
                "kvpValue": "Sanctions Nexus"
            },
            {
                "kvpKey": "risk_factor.internal_watchlist.value",
                "kvpType": "general.string",
                "kvpValue": "No Historical AML Risk Events"
            },
            {
                "kvpKey": "risk_factor.internal_watchlist.score",
                "kvpType": "general.integer",
                "kvpValue": "10"
            },
            {
                "kvpKey": "risk_factor.internal_watchlist.description",
                "kvpType": "general.string",
                "kvpValue": "FCC Risk Events"
            },
            {
                "kvpKey": "risk_factor.num_adverse.value",
                "kvpType": "general.string",
                "kvpValue": "No flag"
            },
            {
                "kvpKey": "risk_factor.num_adverse.score",
                "kvpType": "general.integer",
                "kvpValue": "10"
            },
            {
                "kvpKey": "risk_factor.num_adverse.description",
                "kvpType": "general.string",
                "kvpValue": "Adverse Information"
            },
            {
                "kvpKey": "risk_factor.wealth.value",
                "kvpType": "general.string",
                "kvpValue": "Not applicable"
            },
            {
                "kvpKey": "risk_factor.wealth.score",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "risk_factor.wealth.description",
                "kvpType": "general.string",
                "kvpValue": "Source of wealth"
            },
            {
                "kvpKey": "risk_factor.fund.value",
                "kvpType": "general.string",
                "kvpValue": "Not applicable"
            },
            {
                "kvpKey": "risk_factor.fund.score",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "risk_factor.fund.description",
                "kvpType": "general.string",
                "kvpValue": "Source of Funds"
            },
            {
                "kvpKey": "risk_factor.cross_border.value",
                "kvpType": "general.string",
                "kvpValue": "Foreign National"
            },
            {
                "kvpKey": "risk_factor.cross_border.score",
                "kvpType": "general.integer",
                "kvpValue": "500"
            },
            {
                "kvpKey": "risk_factor.cross_border.description",
                "kvpType": "general.string",
                "kvpValue": "Cross-Border / Non-Residency Risk"
            },
            {
                "kvpKey": "risk_factor.work_situation.value",
                "kvpType": "general.string",
                "kvpValue": "None"
            },
            {
                "kvpKey": "risk_factor.work_situation.score",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "risk_factor.work_situation.description",
                "kvpType": "general.string",
                "kvpValue": "Occupation Risk"
            },
            {
                "kvpKey": "risk_factor.business.value",
                "kvpType": "general.string",
                "kvpValue": "Not applicable"
            },
            {
                "kvpKey": "risk_factor.business.score",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "risk_factor.business.description",
                "kvpType": "general.string",
                "kvpValue": "Business Risk (ISIC) Description"
            },
            {
                "kvpKey": "risk_factor.residential_country.value",
                "kvpType": "general.string",
                "kvpValue": "None"
            },
            {
                "kvpKey": "risk_factor.residential_country.score",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "risk_factor.residential_country.description",
                "kvpType": "general.string",
                "kvpValue": "Inherent Geographic Risk"
            },
            {
                "kvpKey": "Risk.Level",
                "kvpType": "general.string",
                "kvpValue": "MEDIUM"
            },
            {
                "kvpKey": "Risk.Bracket",
                "kvpType": "general.integer",
                "kvpValue": "2"
            },
            {
                "kvpKey": "Risk.Scorecard",
                "kvpType": "general.string",
                "kvpValue": "default"
            },
            {
                "kvpKey": "Confidence.Level",
                "kvpType": "general.string",
                "kvpValue": "HIGH"
            }
        ],
        "resultState": "CHECKED_SUCCESS_CLEAR",
        "riskLevel": 540
    },
    "checkSummary": {
        "checkDate": "2022-06-30T07:09:20.025Z",
        "checkId": "b134067f-2d0b-b3f0-23c8-a0c9af803ef6",
        "checkPerformedBy": "various",
        "checkSource": "various",
        "checkType": "blacklist,one_plus,idvalidate,pep",
        "confidenceLevel": 81,
        "providerCheckID": "b134067f-2d0b-b3f0-23c8-a0c9af803ef6",
        "resultNotes": [
            {
                "kvpKey": "Action.Recommended",
                "kvpType": "general.string",
                "kvpValue": "FAIL"
            },
            {
                "kvpKey": "Fail.Reason.AttestationFailed",
                "kvpType": "general.string",
                "kvpValue": "Missing documents"
            },
            {
                "kvpKey": "Important.AttestationFailed.MissingDocs",
                "kvpType": "general.string",
                "kvpValue": "true"
            },
            {
                "kvpKey": "Info.MissingChecks",
                "kvpType": "general.string",
                "kvpValue": "pep"
            },
            {
                "kvpKey": "Info.NameMatchCount",
                "kvpType": "general.integer",
                "kvpValue": "2"
            },
            {
                "kvpKey": "Info.AddressMatchCount",
                "kvpType": "general.integer",
                "kvpValue": "1"
            },
            {
                "kvpKey": "Info.DoBMatchCount",
                "kvpType": "general.integer",
                "kvpValue": "2"
            },
            {
                "kvpKey": "Info.GovIDMatchCount",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "Info.OtherIDMatchCount",
                "kvpType": "general.integer",
                "kvpValue": "0"
            },
            {
                "kvpKey": "Issue.MEDIUM_RISK",
                "kvpType": "general.bool",
                "kvpValue": "true"
            },
            {
                "kvpKey": "Risk.Policy",
                "kvpType": "general.string",
                "kvpValue": "CDD"
            },
            {
                "kvpKey": "Risk.Level",
                "kvpType": "general.string",
                "kvpValue": "MEDIUM"
            },
            {
                "kvpKey": "Risk.Bracket",
                "kvpType": "general.integer",
                "kvpValue": "2"
            },
            {
                "kvpKey": "Confidence.Level",
                "kvpType": "general.string",
                "kvpValue": "HIGH"
            },
            {
                "kvpKey": "portal.issue.summary",
                "kvpType": "general.string",
                "kvpValue": "ATT-NCMP"
            },
            {
                "kvpKey": "Risk.ResultID",
                "kvpType": "result.id",
                "kvpValue": "03805c74-c7b0-d4c3-1957-5bd0337f882c"
            }
        ],
        "resultState": "UNPROCESSABLE",
        "riskLevel": 540
    },
    "entityProfileResult": {
        "actionRecommended": "FAIL",
        "addressResults": {
            "9f180550-c5d5-cab1-ad45-69bd4c7cc12d": {
                "checked": true,
                "matchCount": 1,
                "matchSources": [
                    "Equifax Public Credit Data Header"
                ],
                "matchType": "curr_addr",
                "nonmatchSources": [
                    "GDC Commercial database (multiple sources) 1"
                ],
                "verified": true
            }
        },
        "checkId": "b134067f-2d0b-b3f0-23c8-a0c9af803ef6",
        "checkResults": [
            {
                "checkClass": "fraud",
                "checkType": "blacklist",
                "name": "Blacklist",
                "result": "PASS"
            },
            {
                "checkClass": "kyc",
                "checkType": "one_plus",
                "name": "1+1",
                "result": "PASS"
            },
            {
                "checkClass": "none",
                "checkType": "idvalidate",
                "code": "MISSING_PREREQUISITE",
                "message": "Attestation check failed. The required documents are not present",
                "name": "IDV",
                "result": "FAIL"
            },
            {
                "checkClass": "aml",
                "checkType": "pep",
                "code": "BLOCKED_BY_OTHER_FAIL",
                "message": "Cannot check while there are failed biometric checks",
                "name": "PEP/Sanctions",
                "result": "UNCHECKED"
            }
        ],
        "checkType": "blacklist,one_plus,idvalidate,pep",
        "entityId": "871f8a04-19f3-b14f-19ae-117845619fc4",
        "issueList": [
            "ATT-NCMP"
        ],
        "kycResults": [
            {
                "matchCount": 2,
                "matchCountRequired": 1,
                "matchTypes": {
                    "name": {
                        "checked": true,
                        "matchCount": 2,
                        "matchSources": [
                            "Equifax Public Credit Data Header",
                            "GDC Commercial database (multiple sources) 2"
                        ],
                        "nonmatchSources": [
                            "Australian Electoral Roll"
                        ],
                        "verified": true
                    }
                },
                "verified": true
            },
            {
                "matchCount": 3,
                "matchCountRequired": 1,
                "matchTypes": {
                    "address": {
                        "checked": true,
                        "matchCount": 1,
                        "matchSources": [
                            "Equifax Public Credit Data Header"
                        ],
                        "nonmatchSources": [
                            "GDC Commercial database (multiple sources) 1"
                        ],
                        "verified": true
                    },
                    "dob": {
                        "checked": true,
                        "matchCount": 2,
                        "matchSources": [
                            "Equifax Public Credit Data Header",
                            "GDC Commercial database (multiple sources) 2"
                        ],
                        "nonmatchSources": [
                            "Australian Public Phone Directory"
                        ],
                        "verified": true
                    }
                },
                "verified": true
            }
        ],
        "latestCheckDate": "2022-06-30T07:09:19.975Z",
        "policyName": "default",
        "profileName": "international",
        "riskLevel": "MEDIUM",
        "riskPolicy": "CDD"
    },
    "entityResult": {
        "addressesCheck": [
            {
                "address": {
                    "addressId": "9f180550-c5d5-cab1-ad45-69bd4c7cc12d",
                    "addressType": "RESIDENTIAL1",
                    "country": "USA",
                    "endDate": "0001-01-01",
                    "longForm": "1200 SW Orleans Street, Topeka, KS 66604",
                    "postalCode": "66604",
                    "startDate": "0001-01-01",
                    "state": "KS",
                    "streetName": "SW Orleans",
                    "streetNumber": "1200",
                    "streetType": "Street",
                    "town": "Topeka"
                }
            }
        ],
        "dateOfBirthCheck": {
            "dob": {
                "dateOfBirth": "1974-08-08",
                "yearOfBirth": "1974"
            }
        },
        "entityId": "871f8a04-19f3-b14f-19ae-117845619fc4",
        "genderCheck": {
            "gender": "M"
        },
        "nameCheck": {
            "name": {
                "displayName": "Doug J Jeffries",
                "familyName": "Jeffries",
                "givenName": "Doug",
                "middleName": "J"
            }
        }
    },
    "requestId": "01G6SQ2P2NTBX7GPQVBDKPXTXF",
    "sharedBlocklistCheckResults": null
}

Next steps

You may wish to modify the entity's details to test verifying other individuals using the available test data. You can also try using a different entity profile.

The FrankeOne platform can be used for much more than onboarding individual customers. Explore the FrankieOne platform by use case.

Check out Smart UI for an easy way to get up and running with our pre-build onboarding interface.


What’s Next