Income Navigator V2 API Reference
API Overview
Introduction
This document provides information on how to interact with the Nova Credit API to obtain an Income Navigator V2 report.
The best way to get the Income Navigator report using Nova Credit's API is to have your applicants use NovaConnect, an easy-to-use and secure JavaScript module. Visit our Quickstart Guide for all details on how to get Nova Credit API credentials and integrate NovaConnect into your app or website today.
Framework and Protocol
The Nova Credit API is organized around REST. It uses resource-oriented URLs, HTTP response codes, and native HTTP functionality such as authentication and verbs. Note that our APIs are served over HTTPS; HTTP is not supported in production.
Delivery Formats
JSON is the default response format.
Endpoints
Our API host is api.novacredit.com
. (See Quickstart Guide for environment information.)
Our resource URL patterns are:
Endpoint | Description |
---|---|
GET /connect/accesstoken | Retrieves an access token for an applicant's Income Navigator report |
GET /connect/income-navigator/v2/json | Retrieves an applicant's Income Navigator report in JSON form |
GET /connect/income-navigator/v2/files | Retrieves a list of files associated with an application, even if there is no report |
GET /connect/income-navigator/v2/files/<filepath> | Retrieves a file associated with an applicant's Income Navigator report |
GET /connect/status | Retrieves the status of an applicant's Income Navigator report |
GET /connect/bank-accounts/<bankAccountId>/ach-details | Retrieves ACH details for a given bank account after report generation |
Visit our Quickstart Guide to see details on how to call these endpoints with examples.
Data Types & Formats
Data Types
Type | Description |
---|---|
String | Extended character set, numbers and punctuation symbols. This includes non-ASCII language-specific characters such as ß, à, ç, é, and more (all encoded as utf8). |
Integer | A rounded numerical value. |
Float | A 64-bit floating decimal point format. |
Bool | A boolean-flag indicating true or false. |
Object | Nested JSON level with more field-values. |
Array | A value or type array contains a zero or positive amount of elements. The elements can be of any type. |
Data Formats
Format | Description |
---|---|
Timestamp | (String) UTC ISO 8601 data and time format. Full specs according to RFC 3339. Example: 1982-09-26T32:20:50.52Z |
Full Date | (String) UTC ISO 8601 date format. Full date format in YYYY-MM-DD . Example: 1982-09-26 |
Short Date | (String) UTC ISO 8601 date format. Shorter format in YYYY-MM . Example: 1982-09 |
UUID | (String) Universally Unique Identifier according to RFC 4122 |
URI | (String) Uniform Resource Identifier according to RFC 3986 |
Full Version | (String) Semantic versioning. http://semver.org/ |
Report Body
Report Structure
The Income Navigator report has the following high level keys in the JSON:
meta
{object}product
{object}sources
{array}identities
{array}employment
{array}income
{object}account_details
{array}
Example of the JSON structure:
{
"meta": {
...
},
"product": {
...
},
"sources": [
...
],
"identities": [
...
],
"employment": [
...
],
"income": {
...
},
"account_details": [
...
]
}
If there is no data to return in that node, it will not be returned.
Within each node, all fields will be returned. If there is no data to be returned for that field, it will be null
.
meta
Information specific to the report that's been returned.
Field | Format | Notes |
---|---|---|
public_token | UUID | The unique identifier of this report |
user_args | String or null | The input of the userArgs function in NovaConnect. |
created_at | Timestamp | The date the consumer's data was retrieved |
api_version | Full version | The API version used to generate this report |
external_id | String or null | The unique applicant identifier of the report from your system. |
status | String | The status for this report. If a report is available, the status will be SUCCESS |
substatus | String or null | The substatus for the report. See substatuses. |
nova_report_revision | String or null | The revision name for this report. This field will be null if this report has never been revised. |
Example:
"meta": {
"public_token": "ff0886a4-f3ff-11e6-bc64-92361f002671",
"user_args": "235234224",
"created_at": "2024-01-13T11:07:46.51Z",
"api_version": "2.0.0",
"external_id": "d167c6bb-225c-461c-be63-f0bc3a1f62ea",
"status": "SUCCESS",
"substatus": null,
"nova_report_revision": null
}
product
Details of the product
the applicant applied for. Please refer to the Client-Side Integration section in the Quickstart Guide.
Field | Format | Notes |
---|---|---|
name | String | Product name |
product_id | UUID | The unique identifier for the product |
inquiry_type | String | See product inquiry_type values |
Example:
{
"product": {
"name": "Village Communities",
"product_id": "9cf178e0-760e-11e7-abf3-5da9d338ae4b",
"inquiry_type": "TENANT"
}
}
sources []
A list of data sources used to build the applicant's report.
Field | Format | Notes |
---|---|---|
source_id | String | See source_id |
source_type | String | See source_types |
status | String | The final status for the source. See status |
Example:
{
"sources": [
{
"source_id": "USA_FIN",
"source_type": "BANK_TRANSACTION",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
]
}
identities []
The applicant's personal identity information reported from each data source.
Field | Format | Notes |
---|---|---|
source_id | String | The identifier for the source that reported the identity information. See sources |
source_record_id | UUID or null | The identifier for an individual record within a source |
first_name | String or null | |
last_name | String or null | |
full_name | String or null | |
emails | Array of String | |
matching | Object | See matching |
Example snippet of identities a report with a bank source:
{
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "raymond",
"last_name": "Marshal",
"full_name": "raymond Marshal",
"emails": ["raymond@email.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "USA_FIN"
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL MARINA MARSHAL",
"emails": []
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL",
"emails": []
}
]
}
Example snippet of identities a report with a paystub source:
{
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "Emelia",
"last_name": "Gutierrez",
"full_name": "Emelia Gutierrez",
"emails": ["emelia@email.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "OCROLUS"
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "OCROLUS",
"source_record_id": "4724127c-a3aa-4c71-b07e-6d287878b439",
"first_name": null,
"last_name": null,
"full_name": "EMELIA GUTIERREZ",
"emails": []
}
]
}
matching
Information about sources which have matching and conflicting values to a particular identity.
matching
is returned in an object broken out by field, only certain fields are matched between sources. If only one identity item exists, there will be no matching field. Information about matching sources is stored wrapped in the MatchingField format, which indicates where each value was sourced from. The matching
node will only be displayed on the identity with source_id
of CONSUMER_INPUT
.
Field | Format | Notes |
---|---|---|
full_name | Object | Matched and unmatched sources for the full name of the applicant |
Example identities matching field object for case where there is a full name match:
{
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "5f19d40f-3c19-4a7d-ad7b-cc28dac40c4d"
}
],
"unmatched_sources": []
}
}
}
Example identities matching field object for case where there is no full name match:
{
"matching": {
"full_name": {
"matched_sources": [],
"unmatched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "c31bf8c7-c25b-4d2c-a4bc-61f79fd46e65"
}
]
}
}
}
MatchingField
An object containing information about which sources have a matching value for a field and which sources contain conflicting values for the same field. A source is an object containing a source_id
and a source_record_id
if there are multiple source records.
Field | Format | Notes |
---|---|---|
matched_sources | Array | List of sources which have a value that matches this identity. See sources |
unmatched_sources | Array | A list of sources which have a value that conflicts with this identity. See sources |
Example matching field object for case where there is a field match:
{
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "5f19d40f-3c19-4a7d-ad7b-cc28dac40c4d"
}
],
"unmatched_sources": []
}
Example matching field object for case where there is no field match:
{
"matched_sources": [],
"unmatched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "c31bf8c7-c25b-4d2c-a4bc-61f79fd46e65"
}
]
}
employment []
Employment information specific to the applicant whose report is being accessed.
Field | Format | Notes |
---|---|---|
source_id | String | The identifier for the source that reported the employment information. See sources |
source_record_id | UUID or null | The identifier for an individual record within a source |
employer_name | String or null | Name of the applicant's employer |
employer_address_line_1 | String or null | Address line 1 where the applicant's employer is located |
employer_address_line_2 | String or null | Address line 2 where the applicant's employer is located |
employer_city | String or null | City where the applicant's employer is located |
employer_state | String or null | State where the applicant's employer is located |
employment_type | String or null | Type of employment. See employment type |
employment_status | String or null | Status of the applicant's employment. See employment status |
job_title | String or null | Title of the applicant's job |
hire_date | Full Date or null | Employee hire date as stated on the employment source |
estimated_hire_date | Full Date or null | An estimate of the employee hire date. Only has a non-null value when hire_date is null |
matching | Object | See matching |
Example:
{
"employment": [
{
"source_id": "OCROLUS",
"employer_name": "Microsoft",
"employer_address_line_1": "1 Microsoft Way",
"employer_address_line_2": null,
"employer_city": "Redmond",
"employer_state": "Washington",
"employment_type": "fulltime",
"employment_status": "active",
"job_title": "Product Manager",
"hire_date": "2017-04-19",
"estimated_hire_date": null,
"matching": {
"employer_name": {
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "edba0b20-22e5-11eb-916b-452b88954927"
}
],
"unmatched_sources": []
}
}
}
]
}
matching
Information about sources which have matching and conflicting values to a particular employment.
matching
is returned in an object broken out by field, only certain fields are matched between sources. If only one employment item exists, there will be no matching field. Information about matching sources is stored wrapped in the MatchingField format, which indicates where each value was sourced from.
Field | Format | Notes |
---|---|---|
employer_name | Object | Matched and unmatched sources for an employer name |
Example employment matching field object for case where there is an employer name match:
{
"matching": {
"employer_name": {
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "5f19d40f-3c19-4a7d-ad7b-cc28dac40c4d"
}
],
"unmatched_sources": []
}
}
}
Example employment matching field object for case where there is no employer name match:
{
"matching": {
"employer_name": {
"matched_sources": [],
"unmatched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "c31bf8c7-c25b-4d2c-a4bc-61f79fd46e65"
}
]
}
}
}
MatchingField
An object containing information about which sources have a matching value for a field and which sources contain conflicting values for the same field. A source is an object containing a source_id
and a source_record_id
if there are multiple source records.
Field | Format | Notes |
---|---|---|
matched_sources | Array | List of sources which have a value that matches this employer. |
unmatched_sources | Array | A list of sources which have a value that conflicts with this employer. |
Example matching field object for case where there is a field match:
{
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "5f19d40f-3c19-4a7d-ad7b-cc28dac40c4d"
}
],
"unmatched_sources": []
}
Example matching field object for case where there is no field match:
{
"matched_sources": [],
"unmatched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "c31bf8c7-c25b-4d2c-a4bc-61f79fd46e65"
}
]
}
income
Income information specific to the applicant whose report is being accessed. Not included in reports if income information is not found.
Field | Format | Notes |
---|---|---|
summary | Object | See summary |
financial_accounts | Array | See financial accounts |
paystubs | Array | See paystubs |
payroll | Array | See payroll |
revised_report_values | Object | See revised_report_values |
Example of structure:
{
"income": {
"summary": {
...
},
"financial_accounts": [
...
],
"paystubs": [
...
],
"payroll": [
...
],
/* Only in regenerated reports */
"revised_report_values": {
...
}
}
}
summary
A summary of the applicant's annual income.
Field | Format | Notes |
---|---|---|
annual_gross_income | Float | Annualized gross income, rounded to 2 decimal places |
annual_net_income | Float | Annualized net income, rounded to 2 decimal places |
Example:
{
"income": {
"summary": {
"annual_gross_income": 12345.67,
"annual_net_income": 11234.56
}
}
}
financial_accounts []
Income information derived from financial account data.
Field | Format | Notes |
---|---|---|
source_ids | Array | The identifiers for the sources that reported the income information. See sources |
model_version | String | The identifier for the income model version |
model_type | String | See model types |
descriptions | Array | Descriptions of active inflow streams, ordered by size of inflow stream over the past 3 months (max 3 inflow stream descriptions) |
is_consistent | Boolean | Income has been received for the last 3 complete months |
net_recent | Integer | Net (take home) income over the past three complete calendar months annualized |
gross_recent | Integer | Gross income over the past three complete calendar months annualized |
net_annual | Integer | Net (take home) income over the past twelve complete calendar months |
gross_annual | Integer | Gross income over the past twelve complete calendar months |
matched_income | Object | See matched_income |
history | Array | See history |
primary_account_detected | Boolean | Represents whether any connected account was determined to be a primary account. This field is only available for Income Model Suite version 2.0. Please contact your Nova Credit account representative if you are interested in enabling this field. |
job_irregularity_risk | String | See job_irregularity_risk. This field is only available for Income Model Suite version 2.0. Please contact your Nova Credit account representative if you are interested in enabling this field. |
inflows | Array | See inflows. This field is only available for Income Model Suite version 2.0. Please contact your Nova Credit account representative if you are interested in enabling this field. |
matched_income_sources | Array | See matched_income_sources. This field is only available for Income Model Suite version 2.0. Please contact your Nova Credit account representative if you are interested in enabling this field. |
Example:
{
"income": {
"financial_accounts": [
{
"source_ids": ["USA_FIN"],
"model_version": "1.1.0",
"model_type": "NOVA_INCOME",
"descriptions": ["GUSTO PAY", "NAPOLI PIZZERIA DIR DEP"],
"is_consistent": true,
"net_recent": 20000,
"gross_recent": 24000,
"net_annual": 20000,
"gross_annual": 24000,
"matched_income": {
"stated_employer": "Napoli Pizzeria",
"stated_annual_income": 18000,
"description": "NAPOLI PIZZERIA USA 6787 836XNLNKSEYCQ8B -",
"net_income": 15480,
"gross_income": 18923
},
"history": [
{
"year": 2019,
"gross": [ 2500, 5000, ... ],
"net": [ 2250, 4500, ... ]
},
]
},
]
}
}
matched_income
An object that describes the income stream that best matches the stated employer name provided by the applicant. If no income stream matches, this object will not be returned.
matched_income
will only be available and filled out if statedEmployerName
was provided by the applicant, and a match was found.
Field | Format | Notes |
---|---|---|
stated_employer | String or null | Stated employer name provided by the applicant |
stated_annual_income | Integer or null | Stated annual income provided by the applicant |
description | String or null | Description for the matched income stream |
net_income | Integer or null | Net income for the matched income stream |
gross_income | Integer or null | Gross income for the matched income stream |
Example:
{
"matched_income": {
"stated_employer": "Napoli Pizzeria",
"stated_annual_income": 18000,
"description": "NAPOLI PIZZERIA USA 6787 836XNLNKSEYCQ8B -",
"net_income": 15480,
"gross_income": 18923
}
}
history []
An array with each element containing information about the value of the income history.
history
is returned in an array of objects (one object per year, from most recent to least). There are multiple histories that the history
node reports and are denoted by separate keys in each history
object. History arrays will be segmented by month. The first element is the month of December and the last is January. If no data is available for a given month the value will be null
Field | Format | Notes |
---|---|---|
year | Integer | The history's given year |
gross | Array | Sums of gross income over 1-month periods. Current month may be partial value |
net | Array | Sums of take-home income over 1-month periods. Current month may be partial value |
Example:
{
"history": [{
"year": 2019,
"gross": [ 2500, 5000, ... ],
"net": [ 2250, 4500, ... ]
}],
},
inflows []
An array with each element containing information about inflows which have been marked as income. An inflow is a group of transactions that represents a single income stream (e.g., from a single employer).
If no inflows marked as income were found, this array may be empty.
inflows
will only be available as a property if at least version 2.0.0 of the Income Model Suite was utilized.
Field | Format | Notes |
---|---|---|
inflow_id | String | A unique identifier for the inflow |
description | String | A short description of the inflow |
deposited_annual_income | Number | Sum of all deposits for the inflow over the last twelve months. If fewer than twelve months are available, the data from the available months will be annualized. |
deposited_recent_income | Number | Sum of all deposits for the inflow over the last three months annualized |
Example:
{
"inflows": [
{
"inflow_id": "3222a843-9768-406b-907c-b2f9a3dc669e",
"description": "CLERICAL-TECHNIC PAYROLL PPD ID: ******7683",
"deposited_annual_income": 31403.93,
"deposited_recent_income": 34520.64
},
{
"inflow_id": "1a84f67b-0ed1-450a-a78e-0e101755cc09",
"description": "IRS TREAS 310 TAX REF PPD ID: ******6170",
"deposited_annual_income": 3115,
"deposited_recent_income": 0
},
{
"inflow_id": "804636ca-8630-4609-93c0-5f6c07331a8e",
"description": "STATEOFMICHIGAN PMT/REFUND PPD ID: 014-INCTAX",
"deposited_annual_income": 716,
"deposited_recent_income": 0
}
]
}
matched_income_sources []
An array with each element containing information about any stated employer names provided by the applicant which were determined to match with an inflow.
If no matches between stated employer names and inflows could be found, this array may be empty.
Each stated employer may match with more than one inflow, but each inflow will only ever have a maximum of one stated employer match.
matched_income_sources
will only be available as a property if at least version 2.0.0 of the Income Model Suite was utilized, and statedEmployerNames
was provided by the applicant.
Field | Format | Notes |
---|---|---|
stated_employer | String | The name of the stated employer that was determined to match an inflow |
matched_inflow_id | String | The unique identifier of the inflow that was determined to match the stated employer. See inflows |
Example:
{
"matched_income_sources": [
{
"stated_employer": "Clerical Technic",
"matched_inflow_id": "3222a843-9768-406b-907c-b2f9a3dc669e"
}
]
}
paystubs []
Income information derived from paystub data.
Field | Format | Notes |
---|---|---|
source_id | String | The identifier for the source that reported the paystub information. See sources |
source_record_id | UUID | The identifier for an individual record within a source |
source_filepath | String | The file path used for downloading an applicants paystub file |
employee_name | String or null | Name of applicant |
employee_address_line_1 | String or null | Address line 1 of applicant |
employee_address_line_2 | String or null | Address line 2 of applicant |
employee_city | String or null | City of applicant |
employee_state | String or null | State of applicant |
employee_zip | String or null | Postal code of applicant |
pay_period_start | Full Date or null | Start date of the paystub pay period |
pay_period_end | Full Date or null | End date of the paystub pay period |
pay_date | Full Date or null | Date the pay was issued |
pay_frequency | String or null | See pay_frequency table |
paystub_provider | String or null | Provider of paystub |
hire_date | Full Date or null | Employee hire date as stated on the paystub |
net_total_earnings_amount_current | Float or null | Net total earnings from current pay period |
net_total_earnings_amount_ytd | Float or null | Net total earnings from year to date pay period |
gross_total_earnings_amount_current | Float or null | Gross total earnings from current pay period |
gross_total_earnings_amount_ytd | Float or null | Gross total earnings from year to date pay period |
regular_pay_earnings_amount_current | Float or null | Regular (base) pay earnings from current pay period |
regular_pay_earnings_amount_ytd | Float or null | Regular (base) pay earnings from year to date pay period |
bonus_earnings_amount_current | Float or null | Bonus earnings from current pay period period |
bonus_earnings_amount_ytd | Float or null | Bonus earnings from year to date pay period |
overtime_earnings_amount_current | Float or null | Overtime earnings from current pay period |
overtime_earnings_amount_ytd | Float or null | Overtime earnings from year to date pay period |
commission_earnings_amount_current | Float or null | Commission earnings from current pay period |
commission_earnings_amount_ytd | Float or null | Commission earnings from year to date pay period |
paid_time_off_earnings_amount_current | Float or null | Paid time off earnings from current pay period |
paid_time_off_earnings_amount_ytd | Float or null | Paid time off earnings from year to date pay period |
vacation_earnings_amount_current | Float or null | Vacation earnings from current pay period |
vacation_earnings_amount_ytd | Float or null | Vacation earnings from year to date pay period |
paid_time_off_deductions_amount_current | Float or null | Paid time off deductions from current pay period |
paid_time_off_deductions_amount_ytd | Float or null | Paid time off deductions from year to date pay period |
vacation_deductions_amount_current | Float or null | Vacation deductions from current pay period |
vacation_deductions_amount_ytd | Float or null | Vacation deductions from year to date pay period |
medicare_tax_deductions_amount_current | Float or null | Medicare tax deductions from current pay period |
medicare_tax_deductions_amount_ytd | Float or null | Medicare tax deductions from year to date pay period |
social_security_deductions_amount_current | Float or null | Social security tax deductions from current pay period |
social_security_deductions_amount_ytd | Float or null | Social security tax deductions from year to date pay period |
fica_tax_deductions_amount_current | Float or null | FICA tax deductions from current pay period |
fica_tax_deductions_amount_ytd | Float or null | FICA tax deductions from year to date pay period |
insights | Object | See insights |
consistency_checks | Object | See consistency_checks |
irregularity_detection | Object | See irregularity_detection |
Example:
{
"income": {
...
"paystubs": [
{
"source_id": "OCROLUS",
"source_record_id": "c33632a0-1d6a-11eb-806e-1f1356d092eb",
"source_filepath": "f3f0d372-a0f7-402f-835e-67ce6db2a75f/866c943a-8e0b-45c6-b381-53712c2809a2.pdf",
"employee_name": "PAYTON STUBBINS",
"employee_address_line_1": "123 FRANKLIN ST",
"employee_address_line_2": "APT 4",
"employee_city": "CHAPEL HILL",
"employee_state": "NC",
"employee_zip": "27517",
"pay_period_start": "2017-07-10",
"pay_period_end": "2017-07-23",
"pay_date": "2017-08-04",
"pay_frequency": "SEMI_MONTHLY",
"paystub_provider": "ADP",
"hire_date": null,
"net_total_earnings_amount_current": 1040.23,
"net_total_earnings_amount_ytd": 18396.25,
"gross_total_earnings_amount_current": 1627.74,
"gross_total_earnings_amount_ytd": 28707.21,
"regular_pay_earnings_amount_current": 1515.84,
"regular_pay_earnings_amount_ytd": 24743.49,
"bonus_earnings_amount_current": 40.69,
"bonus_earnings_amount_ytd": 325.27,
"overtime_earnings_amount_current": "0",
"overtime_earnings_amount_ytd": 442.54,
"commission_earnings_amount_current": null,
"commission_earnings_amount_ytd": null,
"paid_time_off_earnings_amount_current": "0",
"paid_time_off_earnings_amount_ytd": 1459.97,
"vacation_earnings_amount_current": 71.21,
"vacation_earnings_amount_ytd": 952.9,
"paid_time_off_deductions_amount_current": null,
"paid_time_off_deductions_amount_ytd": null,
"vacation_deductions_amount_current": null,
"vacation_deductions_amount_ytd": null,
"medicare_tax_deductions_amount_current": 22.12,
"medicare_tax_deductions_amount_ytd": 394.81,
"social_security_deductions_amount_current": 94.58,
"social_security_deductions_amount_ytd": 1688.15,
"fica_tax_deductions_amount_current": null,
"fica_tax_deductions_amount_ytd": null,
"insights": {
"annual_gross_income": 12345.67,
"annual_net_income": 11234.56
},
"consistency_checks": {
"START_DATE_BEFORE_END_DATE": {
"boolean_value": true
},
"GROSS_PAY_YTD_GREATER_THAN_OR_EQUAL_TO_GROSS_PAY_CURRENT": {
"boolean_value": true
},
"NET_PAY_LESS_THAN_OR_EQUAL_TO_GROSS_PAY": {
"boolean_value": true
},
"COMPONENT_EARNINGS_LESS_THAN_OR_EQUAL_TO_TOTAL_GROSS_PAY": {
"boolean_value": true
},
"EMPLOYEE_NAME_EXISTS": {
"boolean_value": true
},
"EMPLOYER_NAME_EXISTS": {
"boolean_value": true
},
"START_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"END_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"PAY_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"START_DATE_EXISTS": {
"boolean_value": true
},
"END_DATE_EXISTS":{
"boolean_value": true
},
"PAY_DATE_EXISTS": {
"boolean_value": true
},
"GROSS_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
},
"NET_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
}
},
"irregularity_detection": {
"status": "DETECTED",
"reasons": [
{
"reason": "Edited Content Detected",
"severity": "Low Risk"
}
],
"file_type": "pdf",
"genuine_pdf": null,
"version": "3.0"
}
}
]
},
}
insights
An object containing various insights from the paystub.
Field | Format | Notes |
---|---|---|
annual_gross_income | Float or null | Annualized gross income based on paystub information, rounded to 2 decimal places |
annual_net_income | Float or null | Annualized net income based on paystub information, rounded to 2 decimal places |
Example:
{
"insights": {
"annual_gross_income": 12345.67,
"annual_net_income": 11234.56
}
}
consistency_checks
An object containing various consistency checks for the paystub. Each check contains an object with a a boolean_value
representing whether the check has passed or not.
Field | Notes |
---|---|
START_DATE_BEFORE_END_DATE | Indicates whether the start date of the pay period is before the end date of the pay period |
GROSS_PAY_YTD_GREATER_THAN_OR_EQUAL_TO_GROSS_PAY_CURRENT | Indicates whether the year to date gross earnings are greater than or equal to the gross earnings for the pay period |
NET_PAY_LESS_THAN_OR_EQUAL_TO_GROSS_PAY | Indicates whether the net earnings or less than or equal to the gross earnings |
COMPONENT_EARNINGS_LESS_THAN_OR_EQUAL_TO_TOTAL_GROSS_PAY | Indicates whether the sum of the earnings components is less than or equal to the total gross pay |
EMPLOYEE_NAME_EXISTS | Indicates whether the employee name was able to be determined from the paystub |
EMPLOYER_NAME_EXISTS | Indicates whether the employer name was able to be determined from the paystub |
START_DATE_IS_VALID_DATE | Indicates whether the start date of the pay period is an actual date on the Gregorian calendar |
END_DATE_IS_VALID_DATE | Indicates whether the end date of the pay period is an actual date on the Gregorian calendar |
PAY_DATE_IS_VALID_DATE | Indicates whether the pay date is an actual date on the Gregorian calendar |
START_DATE_EXISTS | Indicates whether the start date of the pay period was able to be determined from the paystub |
END_DATE_EXIST | Indicates whether the end date of the pay period was able to be determined from the paystub |
PAY_DATE_EXISTS | Indicates whether the pay date was able to be determined from the paystub |
GROSS_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS | Indicates whether the gross total earnings was able to be determined from the paystub |
NET_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS | Indicates whether the net total earnings was able to be determined from the paystub |
Example:
{
"consistency_checks": {
"START_DATE_BEFORE_END_DATE": {
"boolean_value": true
},
"GROSS_PAY_YTD_GREATER_THAN_OR_EQUAL_TO_GROSS_PAY_CURRENT": {
"boolean_value": true
},
"NET_PAY_LESS_THAN_OR_EQUAL_TO_GROSS_PAY": {
"boolean_value": true
},
"COMPONENT_EARNINGS_LESS_THAN_OR_EQUAL_TO_TOTAL_GROSS_PAY": {
"boolean_value": true
},
"EMPLOYEE_NAME_EXISTS": {
"boolean_value": true
},
"EMPLOYER_NAME_EXISTS": {
"boolean_value": true
},
"START_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"END_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"PAY_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"START_DATE_EXISTS": {
"boolean_value": true
},
"END_DATE_EXISTS": {
"boolean_value": true
},
"PAY_DATE_EXISTS": {
"boolean_value": true
},
"GROSS_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
},
"NET_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
}
}
}
irregularity_detection
If Irregularity Detection is enabled, this node will contain details about any irregularities detected.
Field | Format | Notes |
---|---|---|
status | String | See irregularity_detection_status values |
reasons | Array | See irregularity_detection_reasons values |
file_type | String or null | See irregularity_detection_file_types values |
genuine_pdf | Boolean or null | True only if document is exceptionally genuine, not provided otherwise |
version | String | The version of the fraud algorithm used to generate the results |
Example irregularity_detection field with status NOT_DETECTED
and the genuine_pdf
flag:
{
"irregularity_detection": {
"status": "NOT_DETECTED",
"reasons": [],
"file_type": "pdf",
"genuine_pdf": true,
"version": "3.0"
}
}
Example irregularity_detection field with status REVIEW
:
{
"irregularity_detection": {
"status": "REVIEW",
"reasons": [
{
"reason": "Edited Content Detected",
"severity": "Low Risk"
}
],
"file_type": "pdf",
"genuine_pdf": null,
"version": "3.0"
}
}
Example irregularity_detection field with status DETECTED
and multiple reasons:
{
"irregularity_detection": {
"status": "DETECTED",
"reasons": [
{
"reason": "Edited Content Detected",
"severity": "High Risk"
},
{
"reason": "Unusual Document Source Detected",
"severity": "Medium Risk"
}
],
"file_type": "pdf",
"genuine_pdf": null,
"version": "3.0"
}
}
irregularity detection reasons []
Specific reasons supporting the provided irregularity_detection
status.
Field | Format | Notes |
---|---|---|
reason | String | See the irregularity_detection_reason table |
severity | String | See the irregularity_detection_severity table |
payroll []
Income information derived from payroll data.
Field | Format | Notes |
---|---|---|
source_id | String | The identifier for the source that reported the payroll information. See sources |
provider_name | String | Name of the provider of payroll |
annual_salary_rate | Float or null | Employee annual salary rate as reported by the payroll provider. Will be null if not provided |
estimated_gross_annual_income | Float | Estimate of the gross annual income |
estimated_net_annual_income | Float | Estimate of the net annual income |
pay_period_start | Full Date or null | Start date of the current payroll pay period |
pay_period_end | Full Date or null | End date of the current payroll pay period |
pay_frequency | String | See pay_frequency table |
statements | Array | See statements |
Example:
{
"income": {
...
"payroll": [
{
"source_id": "USA_ATOMIC",
"provider_name": "ADP",
"annual_salary_rate": 45000.54,
"estimated_gross_annual_income": 47500.38,
"estimated_net_annual_income": 30000.12,
"pay_period_start": "2020-06-13",
"pay_period_end": "2020-06-27",
"pay_frequency": "WEEKLY",
"statements": [
{
"pay_date": "2020-06-30",
"gross_total_earnings_amount_current": 1225,
"gross_total_earnings_amount_ytd": 13625,
"net_total_earnings_amount_current": 840,
"net_total_earnings_amount_ytd": 8840
},
{
"pay_date": "2020-06-15",
"gross_total_earnings_amount_current": 1175,
"gross_total_earnings_amount_ytd": 12400,
"net_total_earnings_amount_current": 800,
"net_total_earnings_amount_ytd": 8000
}
]
}
]
}
}
statements []
A list of statement details
Field | Format | Notes |
---|---|---|
pay_date | Full Date | Date the pay was issued |
gross_total_earnings_amount_current | Float or null | Gross total earnings from current pay period |
gross_total_earnings_amount_ytd | Float or null | Gross total earnings from year to date pay period |
net_total_earnings_amount_current | Float or null | Net total earnings from current pay period |
net_total_earnings_amount_ytd | Float or null | Net total earnings from year to date pay period |
Example:
[
{
"pay_date": "2020-06-15",
"gross_total_earnings_amount_current": 1175,
"gross_total_earnings_amount_ytd": 12400,
"net_total_earnings_amount_current": 800,
"net_total_earnings_amount_ytd": 8000
}
]
revised_report_values
Income estimations that have been calculated manually by the Nova Credit Helpdesk in order to address a consumer's dispute. Only included when the report is regenerated due to it needing a correction to the income estimates.
Example revised_report_values field object when consumer has connected at least one bank account with sufficient transactions:
{
"revised_report_values": {
"gross_annual": 45000,
"net_annual": 32000,
"gross_recent": 49000,
"net_recent": 35000
}
}
Example revised_report_values field object when consumer has connected a payroll provider, or uploaded paystubs:
{
"revised_report_values": {
"gross_annual": 45000,
"net_annual": 32000
}
}
Income information computed by the Nova Credit Helpdesk.
Field | Format | Notes |
---|---|---|
gross_annual | Float | Gross income over the past twelve complete calendar months |
net_annual | Float | Net (take home) income over the past twelve complete calendar months |
gross_recent | Float | Gross income over the past three complete calendar months annualized. Only included when the consumer has connected bank accounts. |
net_recent | Float | Net (take home) income over the past three complete calendar months annualized. Only included when the consumer has connected bank accounts. |
account_details []
An array with each instance containing details about an account. The array can have zero objects, and there is no upper bound. To retrieve ACH info associated with an account_id
, use the ACH Details Endpoint.
Field | Format | Notes |
---|---|---|
source_id | UUID | The identifier for the source that reported the account details |
account_id | UUID | Unique identifier for the account |
owner_full_name | String or null | Full name of the owner of the account |
institution_name | String or null | Name of institution such as Chase or Bank of America |
account_name | String | Name of the account within the bank |
account_type | String or null | Type of the account within the bank. See account types |
date_opened | Full Date or null | Date the account was opened |
truncated_account_number | String or null | If available, the last four digits of the account number |
responsibility | String or null | See responsibility |
addresses | Array | See addresses |
current_balance | Float or null | Current balance of the account |
Example:
{
"account_details": [{
"source_id": "USA_FIN",
"account_id": "36139831-0a91-4d1f-bc3e-edc908a978c6",
"owner_full_name": "John Doe",
"institution_name": "CHASE",
"account_name": "INVESTMENT ACCOUNT",
"account_type": "INVESTMENT",
"date_opened": "2015-05-01",
"truncated_account_number": "1234",
"responsibility": "INDIVIDUAL",
"addresses": [
{
"address_id": "80421b7e-7918-4963-b5fb-85055c2994b7",
"address": "225 Valencia St.",
"street": "Valencia St.",
"city": "San Francisco",
"zipcode": "94103",
"state": "CA"
}
],
"current_balance": 23422
},
...
],
}
addresses []
Addresses is a history of contact information attached to this account. Addresses are returned in an array, can have zero objects, and there is no upper bound.
Field | Format | Notes |
---|---|---|
address_id | UUID | Unique identifier for the address |
address | String | The full mailing address of the account owner |
street | String | The street address where the account owner is located |
city | String | The city where the account owner is located |
zipcode | String | The zip code where the account owner is located |
state | String | The state where the account owner is located |
Example:
{
"addresses": [{
"address_id": "80421b7e-7918-4963-b5fb-85055c2994b7",
"address": "225 Valencia St., San Francisco, CA 94103",
"street": "Valencia St.",
"city": "San Francisco",
"zipcode": "94103",
"state": "CA"
}],
},
Tables
account_type
Values of the account_type
field.
Value |
---|
CASH_EQUIVALENT |
CREDIT_CARD |
INVESTMENT |
INSTALLMENT |
MORTGAGE |
OTHER |
employment_status
Values of the employment[].employment_status
field.
Value |
---|
active |
terminated |
employment_type
Values of the employment[].employment_type
field.
Value |
---|
contract |
fulltime |
parttime |
inquiry_type
The human-readable labels are shown when creating and viewing products in the Nova Credit Dashboard. The value column shows the values that are returned in the JSON.
Human-readable label | Value |
---|---|
Monitoring | MONITORING |
Credit Card | CREDIT_CARD |
Vehicle Auto | VEHICLE_AUTO |
Vehicle Other | VEHICLE_OTHER |
Mortgage | MORTGAGE |
Personal | PERSONAL |
Student | STUDENT |
Utility | UTILITY |
Commercial | COMMERCIAL |
Consumer | CONSUMER |
Tenant Screening | TENANT |
Other | OTHER |
model_type
Values of the model_type
field.
Value | Description |
---|---|
NOVA_INCOME | The Nova Credit Income Model |
pay_frequency
Values of the pay_frequency
field.
Value |
---|
null |
MONTHLY |
BI_WEEKLY |
WEEKLY |
SEMI_MONTHLY |
irregularity_detection_status
Values of the status
field in the irregularity_detection
node.
Value | Description |
---|---|
NOT_DETECTED | No irregularities were detected on the file |
DETECTED | Irregularities were detected on the file |
REVIEW | Minor fraud indications detected, manual review recommended |
irregularity_detection_file_type
Values of the file_type
field in the irregularity_detection
node.
Value |
---|
pdf |
image |
unsupported |
irregularity_detection_reason
Values of the reason
field in the irregularity_detection
reasons
node.
Value |
---|
Serial Fraud Detected |
Edited Content Detected |
Suspicious Modification Detected |
Browser/Os Processed |
No Textual Document Detected |
Unusual Document Source Detected |
Screenshot Detected |
PDF/Image Converted |
Suspicious Format Detected |
Editing Software Detected |
Others |
irregularity_detection_severity
Values of the severity
field in the irregularity_detection
reasons
node.
Value |
---|
High Risk |
Medium Risk |
Low Risk |
job_irregularity_risk
Values of the job_irregularity_risk
field.
Value | Description |
---|---|
LOW_RISK | There is low risk that a consumer has recently experienced a disruption in income |
MEDIUM_RISK | There is medium risk that a consumer has recently experienced a disruption in income |
HIGH_RISK | There is high risk that a consumer has recently experienced a disruption in income |
NOT_ENOUGH_DATA | There is insufficient data to determine if a consumer has recently experienced a disruption in income |
responsibility
Values of the responsibility
field.
Value | Description |
---|---|
INDIVIDUAL | The individual is solely responsible for the account |
JOINT | The individual is jointly responsible for the account |
source_id
A human-readable identifier for the source, unique within the context of the report.
Value | Description |
---|---|
MANUAL | Data was manually entered by the applicant |
OCROLUS | Data was sourced from an uploaded paystub |
USA_AKOYA | Data was sourced from a bank connection through Akoya |
USA_ARGYLE | Data was sourced from a payroll provider through Argyle |
USA_ATOMIC | Data was sourced from a payroll provider through Atomic |
USA_FIN | Data was sourced from a bank connection through Finicity |
USA_MX | Data was sourced from a bank connection through MX |
USA_RAI | Data was sourced through Resistant AI |
source_type
Values of the source_type
field.
Value | Description |
---|---|
BANK_TRANSACTION | Data was sourced from a bank connection |
EMPLOYMENT | Data was sourced from an uploaded paystub |
FRAUD | Data was sourced from fraud analysis |
PAYROLL | Data was sourced from a payroll provider |
MANUAL | Data was manually entered by the applicant |
status
- Terminal means that this status is final and will not change
- Report Available means that a report can be retrieved for the Visit
- Webhook means that there is a webhook available for this status
Status | Description | Terminal? | Report Available? | Webhook? |
---|---|---|---|---|
INVITED | The applicant has been sent an invite, such as through the Invite API or in the Nova Dashboard | ✗ | ✗ | ✗ |
INITIALIZED | The /connect/initialization endpoint has been used | ✗ | ✗ | ✗ |
PENDING | A visit has been initialized upon opening the NovaConnect widget | ✗ | ✗ | ✓ |
SUCCESS | The data source has successfully provided information on the applicant | ✓ | ✓ | ✓ |
EXPIRED | The visit has expired before the applicant was able to complete the flow. This will be sent if no completion 72 hours after initial widget opened, invite sent, or initialization endpoint called | ✓ | ✗ | ✓ |
NOT_AUTHENTICATED | The applicant was unable to verify their identity. | ✓ | ✗ | ✓ |
NON_CONTRIBUTING_APPLICANT | The applicant selected to not contribute income. | ✓ | ✗ | ✓ |
ERROR | An error occurred and the Income Navigator Report could not be compiled. If there isn't a detailed substatus, send a message to your Nova Credit Representative with the publicToken | ✓ | ✗ | ✓ |
SUPPLIER_UNRESPONSIVE | The applicant has encountered a data supplier outage while going through the widget. They may need to go through NovaConnect again at a later time | ✓ | ✗ | ✓ |
substatus
Additional insight on certain cases that occur when fetching or parsing a report.
These substatuses may accompany a report with a SUCCESS
status.
Value | Income Model Suite Version 1.1 & 1.2 | **Income Model Suite Version 2.0 ** |
---|---|---|
ACCOUNT_TOO_NEW |
|
|
NO_RECENT_USABLE_INFORMATION |
|
|
NO_USABLE_INCOME_INFORMATION |
|
|
Note: Contact your account team to determine which description applies based on your income model version
These substatuses may accompany a webhook with a NON_CONTRIBUTING_APPLICANT
status:
Value | Description |
---|---|
COAPPLICANT_GUARANTOR_PROVIDING | The applicant selected to not contribute income because their co-applicant or guarantor will provide income instead. |
These substatuses may accompany a webhook with an ERROR
status:
Value | Description |
---|---|
INCOMPATIBLE_ACCOUNT_TYPES_SUBMITTED | The user only submitted debt accounts (e.g. credit card). |
INCOMPLETE_INFORMATION | The source did not provide critical fields |
INVALID_PREFILLS_PII_MISSING | Prefills required for the IN Report are missing. |
INVALID_PREFILL_KEY | A prefill field has been passed in that is not supported for the current API version. (Only returned in sandbox.) |
INVALID_PREFILL_ADDRESS | The address sent via prefill must be a string with max length 100 characters and contain a valid street address. |
INVALID_PREFILL_CITY | The city sent via prefill must be a string with max length 100. |
INVALID_PREFILL_DOB | The birthday sent via prefill is missing or not in YYYY-MM-DD format. |
INVALID_PREFILL_EMAIL | The email sent via prefill must be a valid email with max length 100 characters. |
INVALID_PREFILL_FIRST_NAME | The first name sent via prefill must be a string less than 255 characters and contain only alphabetical, unicode, dots, apostraphes and dashes. |
INVALID_PREFILL_LAST_NAME | The last name sent via prefill must be a string less than 255 characters and contain only alphabetical, unicode, dots, apostraphes and dashes. |
INVALID_PREFILL_INCOME | The stated annual income sent via prefill must be an integer between 0 and 2147483647. |
INVALID_PREFILL_PHONE | The phone number sent via prefill must be a string with max length 255 characters. |
INVALID_PREFILL_STATE | The state sent via prefill is missing or not in a valid two letter US state or territory code. |
INVALID_PREFILL_ZIP | The zip code sent via prefill must a string with a valid USA zip code. |
MFA_REQUIRED_ON_FETCH | The bank account the user tried to connect to requires multi-factor authentication and may depend on the user's browser security settings. |
Report Examples
Bank Account
Here's an example response where a user has gone through NovaConnect and connected their bank account.
{
"meta": {
"public_token": "65bf7135-4eb8-4342-a7c2-0380322b3d59",
"user_args": null,
"created_at": "2025-02-07T23:10:51.987Z",
"api_version": "2.0.0",
"status": "SUCCESS",
"substatus": null,
"external_id": null,
"nova_report_revision": null
},
"product": {
"name": "Village Communities",
"product_id": "12d1e755-3d82-445d-84e6-b67b5ff7c70d",
"inquiry_type": "TENANT"
},
"sources": [
{
"source_id": "USA_FIN",
"source_type": "BANK_TRANSACTION",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
],
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "raymond",
"last_name": "Marshal",
"full_name": "raymond Marshal",
"emails": ["raymond@email.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "USA_FIN",
"source_record_id": null
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL",
"emails": []
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL MARINA MARSHAL",
"emails": []
}
],
"account_details": [
{
"source_id": "USA_FIN",
"account_id": "fd058f61-56d3-4150-ad9f-ff899b55f799",
"owner_full_name": "RAYMOND MARSHAL",
"institution_name": "Personal Loan Account",
"account_name": "Checking Account",
"account_type": "CASH_EQUIVALENT",
"date_opened": null,
"truncated_account_number": "475462",
"responsibility": "INDIVIDUAL",
"addresses": [
{
"address_id": "6d4d5fff-25ee-4ba0-8247-9bc75b900378",
"address": "5445 ALTON PKWY IRVINE CA 92614",
"street": null,
"city": null,
"zipcode": null,
"state": null
}
],
"current_balance": 577.63
},
{
"source_id": "USA_FIN",
"account_id": "c100e365-5838-40bc-a8a5-c70be5ebf5f8",
"owner_full_name": "RAYMOND MARSHAL MARINA MARSHAL",
"institution_name": "Personal Loan Account",
"account_name": "Credit Card Account",
"account_type": "INVESTMENT",
"date_opened": null,
"truncated_account_number": "108249",
"responsibility": "JOINT",
"addresses": [
{
"address_id": "ee64a0fe-985b-4f92-acad-603a951ddb9e",
"address": "5445 ALTON PKWY IRVINE CA 92614",
"street": null,
"city": null,
"zipcode": null,
"state": null
}
],
"current_balance": 6300
}
],
"income": {
"summary": {
"annual_gross_income": 10824,
"annual_net_income": 6121
},
"financial_accounts": [
{
"source_ids": ["USA_FIN"],
"model_version": "1.1.0",
"model_type": "NOVA_INCOME",
"descriptions": ["uber"],
"is_consistent": false,
"net_recent": 5525,
"gross_recent": 9770,
"net_annual": 6121,
"gross_annual": 10824,
"history": [
{
"year": 2025,
"gross": [null, null, null, null, null, null, null, null, null, null, 0, 0],
"net": [null, null, null, null, null, null, null, null, null, null, 0, 0]
},
{
"year": 2024,
"gross": [2442, 0, 0, 2120, 0, 2146, 2015, 0, 0, 0, 2101, 2053],
"net": [1381, 0, 0, 1199, 0, 1213, 1139, 0, 0, 0, 1188, 1161]
},
{
"year": 2023,
"gross": [0, 2357, 0, 1973, null, null, null, null, null, null, null, null],
"net": [0, 1339, 0, 1121, null, null, null, null, null, null, null, null]
}
]
}
]
}
}
Pay Stub Upload
{
"meta": {
"public_token": "753c4285-9331-4502-b02b-5064904f33ce",
"user_args": null,
"created_at": "2025-02-07T23:47:23.151Z",
"api_version": "2.0.0",
"status": "SUCCESS",
"substatus": null,
"external_id": null,
"nova_report_revision": null
},
"product": {
"name": "Village Communities",
"product_id": "a8be4941-04a7-405f-b066-48313c7b003b",
"inquiry_type": "OTHER"
},
"sources": [
{
"source_id": "OCROLUS",
"source_type": "EMPLOYMENT",
"status": "SUCCESS"
},
{
"source_id": "USA_RAI",
"source_type": "FRAUD",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
],
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "Emelia",
"last_name": "Gutierrez",
"full_name": "Emelia Gutierrez",
"emails": ["emelia@email.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "OCROLUS",
"source_record_id": "c1367efa-baac-40d5-88f7-7cc680b12509"
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "OCROLUS",
"source_record_id": "c1367efa-baac-40d5-88f7-7cc680b12509",
"first_name": null,
"last_name": null,
"full_name": "EMELIA GUTIERREZ",
"emails": []
}
],
"employment": [
{
"source_id": "OCROLUS",
"source_record_id": "c1367efa-baac-40d5-88f7-7cc680b12509",
"employer_name": "INITECH CORPORATION",
"employer_address_line_1": "1 INITECH WAY",
"employer_address_line_2": null,
"employer_city": "AUSTIN",
"employer_state": "TX",
"employment_type": null,
"employment_status": null,
"job_title": null,
"hire_date": null,
"estimated_hire_date": null
}
],
"income": {
"summary": {
"annual_gross_income": 64910.86,
"annual_net_income": 41518.01
},
"paystubs": [
{
"source_id": "OCROLUS",
"source_record_id": "c1367efa-baac-40d5-88f7-7cc680b12509",
"source_filepath": "36c29b7c-b241-494f-b853-f17b4b1bb718/936def0c-27e0-4c19-a306-aa57eb25dca8.jpg",
"employee_name": "EMELIA GUTIERREZ",
"employee_address_line_1": "123 FRANKLIN ST",
"employee_address_line_2": "APT 4",
"employee_city": "AUSTIN",
"employee_state": "TX",
"employee_zip": "73301",
"pay_period_start": "2025-01-16",
"pay_period_end": "2025-01-31",
"pay_date": "2025-01-31",
"pay_frequency": "SEMI_MONTHLY",
"paystub_provider": "ADP",
"hire_date": null,
"net_total_earnings_amount_current": 1040.23,
"net_total_earnings_amount_ytd": 18396.25,
"gross_total_earnings_amount_current": 1627.74,
"gross_total_earnings_amount_ytd": 28707.21,
"regular_pay_earnings_amount_current": 1515.84,
"regular_pay_earnings_amount_ytd": 24743.49,
"bonus_earnings_amount_current": 40.69,
"bonus_earnings_amount_ytd": 325.27,
"overtime_earnings_amount_current": 0,
"overtime_earnings_amount_ytd": 442.54,
"commission_earnings_amount_current": null,
"commission_earnings_amount_ytd": null,
"paid_time_off_earnings_amount_current": 0,
"paid_time_off_earnings_amount_ytd": 1459.97,
"vacation_earnings_amount_current": 71.21,
"vacation_earnings_amount_ytd": 952.9,
"paid_time_off_deductions_amount_current": null,
"paid_time_off_deductions_amount_ytd": null,
"vacation_deductions_amount_current": null,
"vacation_deductions_amount_ytd": null,
"medicare_tax_deductions_amount_current": 22.12,
"medicare_tax_deductions_amount_ytd": 394.81,
"social_security_deductions_amount_current": 94.58,
"social_security_deductions_amount_ytd": 1688.15,
"fica_tax_deductions_amount_current": null,
"fica_tax_deductions_amount_ytd": null,
"insights": {
"annual_gross_income": 64910.86,
"annual_net_income": 41518.01
},
"consistency_checks": {
"START_DATE_BEFORE_END_DATE": {
"boolean_value": true
},
"GROSS_PAY_YTD_GREATER_THAN_OR_EQUAL_TO_GROSS_PAY_CURRENT": {
"boolean_value": true
},
"NET_PAY_LESS_THAN_OR_EQUAL_TO_GROSS_PAY": {
"boolean_value": true
},
"COMPONENT_EARNINGS_LESS_THAN_OR_EQUAL_TO_TOTAL_GROSS_PAY": {
"boolean_value": true
},
"EMPLOYEE_NAME_EXISTS": {
"boolean_value": true
},
"EMPLOYER_NAME_EXISTS": {
"boolean_value": true
},
"START_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"END_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"PAY_DATE_IS_VALID_DATE": {
"boolean_value": true
},
"START_DATE_EXISTS": {
"boolean_value": true
},
"END_DATE_EXISTS": {
"boolean_value": true
},
"PAY_DATE_EXISTS": {
"boolean_value": true
},
"GROSS_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
},
"NET_TOTAL_EARNINGS_AMOUNT_CURRENT_EXISTS": {
"boolean_value": true
}
},
"irregularity_detection": {
"status": "NOT_DETECTED",
"reasons": [],
"file_type": "pdf",
"genuine_pdf": true,
"version": "3.0"
}
}
]
}
}
Payroll
{
"meta": {
"public_token": "5a6f89d5-8a1e-42af-adeb-f22312638bb9",
"user_args": null,
"created_at": "2025-02-08T00:06:22.076Z",
"api_version": "2.0.0",
"status": "SUCCESS",
"substatus": null,
"external_id": null,
"nova_report_revision": null
},
"product": {
"name": "Village Communities",
"product_id": "422ecccb-942a-47ff-ab73-8a5285c3b2b4",
"inquiry_type": "OTHER"
},
"sources": [
{
"source_id": "USA_ATOMIC",
"source_type": "PAYROLL",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
],
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "Jane",
"last_name": "Appleseed",
"full_name": "Jane Appleseed",
"emails": ["janeappleseed@example.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "USA_ATOMIC",
"source_record_id": null
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "USA_ATOMIC",
"source_record_id": null,
"first_name": "Jane",
"last_name": "Appleseed",
"full_name": null,
"emails": ["janeappleseed@example.com"]
}
],
"employment": [
{
"source_id": "USA_ATOMIC",
"source_record_id": null,
"employer_name": "Enterprise One",
"employer_address_line_1": "12345 Enterprise Rd",
"employer_address_line_2": "Suite 105",
"employer_city": "Salt Lake City",
"employer_state": "UT",
"employment_type": "fulltime",
"employment_status": "active",
"job_title": "Logistics",
"hire_date": "2023-01-01",
"estimated_hire_date": null
}
],
"income": {
"summary": {
"annual_gross_income": 60000,
"annual_net_income": 47400
},
"payroll": [
{
"source_id": "USA_ATOMIC",
"provider_name": "Paytomic",
"annual_salary_rate": 60000,
"estimated_gross_annual_income": 60000,
"estimated_net_annual_income": 47400,
"pay_period_start": "2025-01-01",
"pay_period_end": "2025-01-31",
"pay_frequency": "MONTHLY",
"statements": [
{
"pay_date": "2025-01-31",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 10000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 7900
},
{
"pay_date": "2025-01-01",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 5000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 3950
},
{
"pay_date": "2024-12-02",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 60000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 47400
}
]
}
]
}
}
Revised Income
Here's are some example responses where a report was regenerated with manually computed revisions to the income estimates due to a dispute by the consumer.
Bank Account
Here's an example regenerated bank account report.
{
"meta": {
"public_token": "65bf7135-4eb8-4342-a7c2-0380322b3d59",
"user_args": null,
"created_at": "2025-02-07T23:10:51.987Z",
"api_version": "2.0.0",
"status": "SUCCESS",
"substatus": null,
"external_id": null,
"nova_report_revision": "1"
},
"product": {
"name": "Village Communities",
"product_id": "12d1e755-3d82-445d-84e6-b67b5ff7c70d",
"inquiry_type": "TENANT"
},
"sources": [
{
"source_id": "USA_FIN",
"source_type": "BANK_TRANSACTION",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
],
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "raymond",
"last_name": "Marshal",
"full_name": "raymond Marshal",
"emails": ["raymond@email.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "USA_FIN",
"source_record_id": null
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL",
"emails": []
},
{
"source_id": "USA_FIN",
"source_record_id": null,
"first_name": null,
"last_name": null,
"full_name": "RAYMOND MARSHAL MARINA MARSHAL",
"emails": []
}
],
"account_details": [
{
"source_id": "USA_FIN",
"account_id": "fd058f61-56d3-4150-ad9f-ff899b55f799",
"owner_full_name": "RAYMOND MARSHAL",
"institution_name": "Personal Loan Account",
"account_name": "Checking Account",
"account_type": "CASH_EQUIVALENT",
"date_opened": null,
"truncated_account_number": "475462",
"responsibility": "INDIVIDUAL",
"addresses": [
{
"address_id": "6d4d5fff-25ee-4ba0-8247-9bc75b900378",
"address": "5445 ALTON PKWY IRVINE CA 92614",
"street": null,
"city": null,
"zipcode": null,
"state": null
}
],
"current_balance": 577.63
},
{
"source_id": "USA_FIN",
"account_id": "c100e365-5838-40bc-a8a5-c70be5ebf5f8",
"owner_full_name": "RAYMOND MARSHAL MARINA MARSHAL",
"institution_name": "Personal Loan Account",
"account_name": "Credit Card Account",
"account_type": "INVESTMENT",
"date_opened": null,
"truncated_account_number": "108249",
"responsibility": "JOINT",
"addresses": [
{
"address_id": "ee64a0fe-985b-4f92-acad-603a951ddb9e",
"address": "5445 ALTON PKWY IRVINE CA 92614",
"street": null,
"city": null,
"zipcode": null,
"state": null
}
],
"current_balance": 6300
}
],
"income": {
"summary": {
"annual_gross_income": 10824,
"annual_net_income": 6121
},
"financial_accounts": [
{
"source_ids": ["USA_FIN"],
"model_version": "1.1.0",
"model_type": "NOVA_INCOME",
"descriptions": ["uber"],
"is_consistent": false,
"net_recent": 5525,
"gross_recent": 9770,
"net_annual": 6121,
"gross_annual": 10824,
"history": [
{
"year": 2025,
"gross": [null, null, null, null, null, null, null, null, null, null, 0, 0],
"net": [null, null, null, null, null, null, null, null, null, null, 0, 0]
},
{
"year": 2024,
"gross": [2442, 0, 0, 2120, 0, 2146, 2015, 0, 0, 0, 2101, 2053],
"net": [1381, 0, 0, 1199, 0, 1213, 1139, 0, 0, 0, 1188, 1161]
},
{
"year": 2023,
"gross": [0, 2357, 0, 1973, null, null, null, null, null, null, null, null],
"net": [0, 1339, 0, 1121, null, null, null, null, null, null, null, null]
}
]
}
],
"revised_report_values": {
"gross_annual": 45000,
"net_annual": 32000,
"gross_recent": 49000,
"net_recent": 35000
}
}
}
Payroll
Here's an example regenerated payroll report.
{
"meta": {
"public_token": "5a6f89d5-8a1e-42af-adeb-f22312638bb9",
"user_args": null,
"created_at": "2025-02-08T00:06:22.076Z",
"api_version": "2.0.0",
"status": "SUCCESS",
"substatus": null,
"external_id": null,
"nova_report_revision": "1"
},
"product": {
"name": "Village Communities",
"product_id": "422ecccb-942a-47ff-ab73-8a5285c3b2b4",
"inquiry_type": "OTHER"
},
"sources": [
{
"source_id": "USA_ATOMIC",
"source_type": "PAYROLL",
"status": "SUCCESS"
},
{
"source_id": "CONSUMER_INPUT",
"source_type": "MANUAL",
"status": "SUCCESS"
}
],
"identities": [
{
"source_id": "CONSUMER_INPUT",
"source_record_id": null,
"first_name": "Jane",
"last_name": "Appleseed",
"full_name": "Jane Appleseed",
"emails": ["janeappleseed@example.com"],
"matching": {
"full_name": {
"matched_sources": [
{
"source_id": "USA_ATOMIC",
"source_record_id": null
}
],
"unmatched_sources": []
}
}
},
{
"source_id": "USA_ATOMIC",
"source_record_id": null,
"first_name": "Jane",
"last_name": "Appleseed",
"full_name": null,
"emails": ["janeappleseed@example.com"]
}
],
"employment": [
{
"source_id": "USA_ATOMIC",
"source_record_id": null,
"employer_name": "Enterprise One",
"employer_address_line_1": "12345 Enterprise Rd",
"employer_address_line_2": "Suite 105",
"employer_city": "Salt Lake City",
"employer_state": "UT",
"employment_type": "fulltime",
"employment_status": "active",
"job_title": "Logistics",
"hire_date": "2023-01-01",
"estimated_hire_date": null
}
],
"income": {
"summary": {
"annual_gross_income": 60000,
"annual_net_income": 47400
},
"payroll": [
{
"source_id": "USA_ATOMIC",
"provider_name": "Paytomic",
"annual_salary_rate": 60000,
"estimated_gross_annual_income": 60000,
"estimated_net_annual_income": 47400,
"pay_period_start": "2025-01-01",
"pay_period_end": "2025-01-31",
"pay_frequency": "MONTHLY",
"statements": [
{
"pay_date": "2025-01-31",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 10000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 7900
},
{
"pay_date": "2025-01-01",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 5000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 3950
},
{
"pay_date": "2024-12-02",
"gross_total_earnings_amount_current": 5000,
"gross_total_earnings_amount_ytd": 60000,
"net_total_earnings_amount_current": 3950,
"net_total_earnings_amount_ytd": 47400
}
]
}
],
"revised_report_values": {
"gross_annual": 65000,
"net_annual": 49000
}
}
}
Sandbox Environment
The sandbox environment provides a safe testing space to integrate and validate your implementation before going to production. This guide covers everything you need to know about testing in sandbox mode.
Overview
The sandbox environment allows you to:
- Access predefined test user profiles with different data scenarios
- Simulate various response states and error conditions
- Validate your webhook integration
- Test our paystub, payroll, or multi-aggregator bank connection methods (Finicity, Akoya, and MX)
For general information about sandbox vs. production environments, see the Quickstart Guide.
Accessing Sandbox Reports
To retrieve a sandbox report, you must provide specific test user information through the NovaConnect widget's prefill functionality. The prefill data can match one of our predefined test profiles exactly. If the prefill data is different from the user profile you select in the UI, it will appear in unmatched sources
in the matching[] section of the report. You could also prefill using a test email you have access to, that will help you go through the end-to-end user journey.
Required Information
Each test user requires the following prefill fields:
firstName
- The test user's first namelastName
- The test user's last namedateOfBirth
- Date of birth in YYYY-MM-DD formatemail
- The test user's email addressstate
- The test user's state
Learn more about implementing prefill in the Quickstart Guide.
Bank Accounts
We provide eight test user profiles, each designed to simulate different financial scenarios:
Profile Type | First Name | Last Name | Date of Birth | State | Stated Employer | Scenario | Supplier Testing Available | |
---|---|---|---|---|---|---|---|---|
Default User | Raymond | Marshal | 1995-10-01 | raymond@email.com | CA | Raymond's Designs | Complete financial profile with typical transaction history | Finicity |
Single Primary Account | Sarah | Single | 1986-10-12 | sarah@email.com | WA | Boeing | Single checking account with standard transactions | Akoya & Finicity |
Multi-Account | Mike | Many | 1992-05-08 | mike@email.com | TX | Target | Multiple accounts (checking, savings, investment) | Akoya & Finicity |
Joint Account | Jason | Joint | 1976-03-09 | jason@email.com | IL | Microsoft | Joint account ownership with shared responsibility | Akoya & Finicity |
Debt Account Linked | Derek | Debt | 1984-04-12 | derek@email.com | TX | Charles Schwab | Profile with linked debt accounts (credit cards) | Finicity |
No Income | Nolan | NoTransactions | 1992-03-07 | nolan@email.com | IL | Optional | Account with no transaction history | Finicity |
Default User | Cory | Anders | 1989-10-25 | cory@email.com | NY | Optional | Complete financial profile with typical transaction history | MX |
New Account | Nancy | Newman | 1961-07-04 | nancy@email.com | CA | J Industries | Account with less than one month of transactions | Akoya |
Supplier specific testing:
If testing multiple aggregators in sandbox mode, you will need to select a bank before being routed to select one of the pre-configured test profiles above to simulate results. Please select FinBank
to connect with Finicity, Mikomo
to connect with Akoya, and MX Bank
to connect with MX.
If you are provided with a login screen, use the following credentials:
- Username:
demo
- Password:
go
Simulating Error States
You can trigger specific error conditions by using special values in the lastName
field:
Expired Session
- Last Name
expiresoon
- Result: Triggers an
EXPIRED
status in 5 minutes instead of the standard 72 hours - Use Case: Test timeout handling in your integration
Supplier Unresponsive
- Choose FinBank
- Pass Last Name:
supplierdown
- Result: Triggers a
SUPPLIER_UNRESPONSIVE
status - Use Case: Test error handling for aggregator connection failures
Paystub Upload
For testing purposes on the paystub upload page of the Income Navigator widget, we have provided a set of filename combinations that correspond with different outcomes. These are as follows:
Filename | Paystub Outcome | Detect Outcome |
---|---|---|
emelia | SUCCESS (default paystub) | NOT_DETECTED |
emelia_detected | SUCCESS (default paystub) | DETECTED |
empty | NOT_AUTHENTICATED (empty paystub) | N/A |
marie | SUCCESS (thin file paystub) | NOT_DETECTED |
larry | SUCCESS (low income paystub) | NOT_DETECTED |
down | BUREAU_UNRESPONSIVE | N/A |
missingfields | SUCCESS (paystub which is missing fields) | NOT_DETECTED |
Any other filename | NOT_AUTHENTICATED | N/A |
In addition to these filename combinations, we have provided inputs to trigger more complex irregularity detection outcomes.
These inputs should be passed in directly using prefill values, and can be used in combination with the filenames above. Using the emelia_detected filename will always result in an outcome of DETECTED
.
For each outcome below, use a Prefill First Name of getAdaptiveDecisionResult
.
Prefill Last Name | File Type | Irregularity Detection Status |
---|---|---|
pdfTrusted | NOT_DETECTED | |
pdfHighRisk | DETECTED | |
pdfWarningApproved | REVIEW | |
imageTrusted | image | NOT_DETECTED |
imageHighRiskManualReview | image | DETECTED |
Payroll Accounts
USA_ATOMIC
We provide multiple sandbox users for testing: Jane, Alice and Paddy.
To access the reports please pass the first names via Prefill Keys, and then choose Test User
on the Atomic Simulator page.
If you do not enter a name for any of the sandbox users, we will default to the "Jane" report.
Here is some information about each sandbox report:
Report Info | Jane (Default) | Alice | Paddy | Jimmy | Patricia |
---|---|---|---|---|---|
Employment Status | active | terminated | active | active | active |
Employment Type | fulltime | fulltime | fulltime | fulltime | fulltime |
Annual Income | 60000 | 21612 | 156013.2 | 130000 | 52000 |
Pay Frequency | monthly | semimonthly | semimonthly | biweekly | weekly |
NovaConnect Testing
If you are using the sandbox environment, you will see a special Atomic Simulator page instead of the Atomic Widget. This page contains multiple options for testing different widget states. You can test success flows, cascade and various Atomic failure states.
If you are performing production testing, then you can use the Atomic Widget to trigger different testing scenarios. Here is a list of different test cases. The test cases should work for any source provider as long as you enter the name and phone number as specified for each test case.
USA_ARGYLE
We provide multiple sandbox users for testing: Cory, Alex, Sylvia, Cassie, Sarah, Michael, Emma, David, and Lisa.
To access the reports please pass the first names via Prefill Keys, and then choose Test User
on the Argyle Simulator page.
If you do not enter a name for any of the sandbox users, we will default to the "Cory" report.
Here is some information about each sandbox report:
Report Info | Cory (Default) | Alex | Sylvia | Cassie | Sarah | Michael | Emma | David | Lisa |
---|---|---|---|---|---|---|---|---|---|
Employment Status | active | active | active | active | terminated | active | active | active | active |
Employment Type | fulltime | fulltime | contractor | contractor | fulltime | fulltime | fulltime | parttime | fulltime |
Provider Type | Standard | Most Common | Gig (Uber) | Gig (DoorDash) | Most Common | 2nd Most Common | Enterprise | SMB | SMB |
Pay Frequency | various | biweekly | irregular | irregular | biweekly | semimonthly | monthly | weekly | biweekly |
Special Features | Default user | Missing paystubs | 6mo history | No paystubs | Terminated 3mo | Quarterly bonus | YTD amounts | Variable OT | Variable hours |
Webhooks
Webhooks are the mechanism that Nova Credit uses to inform you of core initialization and completion steps for each NovaConnect widget interaction. A session is initialized when the NovaConnect widget is opened. One session can consist of multiple suppliers, and these supplier-flow outcomes are recorded and attached to the webhook body in the history node.
We make a POST API call to the webhook callback URL that you provide. Webhooks can be managed in the Developer tab on the Nova Credit Dashboard, where you must set your callback URL and can toggle your various event subscriptions on and off. Some events or statuses are subscribed to by default.
Webhook Event Types
Each Webhook API call will contain one of the event types listed below in the JSON body:
Event Type | Description |
---|---|
VISIT | A single NovaConnect widget interaction, which can consist of multiple suppliers. Only one terminal status outcome is sent per widget open; other supplier-flow outcomes are recorded and attached to the webhook in the history node |
REGENERATED_VISIT | Only occurs for reports that have been regenerated. This event type also includes a novaReportRevision in the webhook body. |
Webhook Status Codes
View the status table to see the full list of statuses, with the "Webhook" column representing which ones correspond to a webhook call.
Webhook Body
Webhook Body Key | Description |
---|---|
eventType | Event Type (see event type table above) corresponding to this webhook |
status | Status (see status code table above) corresponding to this webhook |
substatus | A more detailed status. See substatus types |
publicToken | Unique UUID associated with this status, which can be used to retrieve the Nova Credit report |
externalId | Optional unique identifier passed in by the Nova Credit customer (you) with this application. This key will only be present if externalId was passed in |
userArgs | Optional string passed in by the Nova Credit customer (you) with this application. This key will only be present if userArgs was passed in |
eventId | Unique ID for the webhook |
eventCreatedTime | Webhook event timestamp |
reportType | The type of Nova Credit report. |
history | An array containing 1 or more objects, containing data on all of the statuses an applicant has reached within one Income Navigator widget instance, sorted by most recent to least recent |
history.eventType | Each history object will have a SUPPLIER event type |
history.companyCode | Data supplier for this history object |
history.dateAttempted | Timestamp marking when this corresponding history object was begun |
history.status | Status (see status code table above) corresponding to this history object |
history.substatus | A more detailed status. See substatus types |
Note that the status will be informed by the most recent supplier event status.
Example:
{
eventType: 'VISIT',
status: 'SUCCESS',
publicToken: '6b986690-458b-11e7-98fb-a71570ea65a6',
externalId: '25ad7063-fe76-437a-b4d8-3662ba4cc9c7',
userArgs: '235234224',
eventId: '028d9354-3991-46c4-97df-bd6c2ff09733',
eventCreatedTime: '2019-09-26T33:15:23.17Z',
history: [
{
eventType: 'SUPPLIER',
status: 'SUCCESS',
companyCode: 'USA_FIN',
dateAttempted: '2019-09-26T19:20:00.00Z' // newest timestamp
},
{
eventType: 'SUPPLIER',
status: 'PENDING',
companyCode: 'USA_FIN',
dateAttempted: '2019-09-26T19:18:00.00Z' // oldest timestamp
}
]
}
Webhook Failures
When a webhook fails we retry posting with an exponential increase in the time between each attempt. For example, the first retry happens after 1 second, the second after 2 seconds etc.
Number of Attempts | Time Until Retry if Unsuccessful |
---|---|
1 | 1 second |
2 | 2 seconds |
3 | 4 seconds |
4 | 8 seconds |
... | ... |
This strategy allows for several retries within a few minutes but expands to daily retries in the case of an outage, allowing customers to restore before receiving the callback. However, if a callback is still unsuccessful after one week we do not continue retrying.
For more information, please visit the server integration section in our Quickstart Guide.
Webhook Signature
Nova Credit optionally signs webhook payloads in order to allow for trust verification of inbound webhook requests.
When configured, the webhook request will contain these additional headers:
Header | Value |
---|---|
X-Timestamp | timestamp of request generation |
X-Nova-Signature | SHA256 HMAC digest of request timestamp and payload, period-delimited. Your Webhook Signatures Secret Key is found under the Webhooks section on the Developer tab of your Nova Credit Dashboard. |
Please contact your Nova Credit account manager to enable this feature.
Example verification of signature:
const crypto = require('crypto');
const signature = req.get('X-Nova-Signature');
const timestamp = req.get('X-Timestamp');
const checkPayload = `${timestamp}.${JSON.stringify(req.body)}`;
const checkDigest = crypto.createHmac('sha256', '< webhook secret key >')
.update(checkPayload)
.digest('base64');
return crypto.timingSafeEquals(signature, checkDigest);
For more information, please visit the server integration section in our Quickstart Guide.
Error Codes & Responses
At Nova Credit, we distinguish between two status message deliveries:
- Delivered by Nova Credit to the webhook
- If you call a resource endpoint Nova Credit provides a status in the response
Resource Endpoint Errors
When an error occurs while calling the endpoints the Nova Credit servers send back a JSON object with the following format:
{
"error": "UNKNOWN_CUSTOMER",
"terminated": true
}
Error Codes
The Nova Credit endpoints return the following HTTP status codes and error messages:
HTTP Status Code | Error | Description |
---|---|---|
200 | - | The request was successful. |
400 | MALFORMED_HEADERS | The request headers are incorrectly formatted. |
400 | MISSING_INPUT | An input is missing that the endpoint expected. |
400 | INVALID_PUBLIC_ID | The public ID is not valid. |
401 | EXPIRED_TOKEN | The access_token you're sending in the request headers has expired. Please request a new one. |
403 | UNKNOWN_CUSTOMER | The public_id or client_id Nova Credit received in the request from is not recognized. Check your credentials in the Nova Credit Dashboard. |
403 | UNAUTHORIZED | The client_id and secret_key combination is not recognized. Check your credentials in the Nova Credit Dashboard. |
403 | ORIGIN_UNAUTHORIZED | The origin of the request is not whitelisted on the Nova Credit servers for CORS. |
404 | INVALID_EXTERNAL_ID | The external ID is not valid. |
404 | INVALID_TOKEN | The public_token or access_token is not valid for reasons other than expiration. |
408 | REQUEST_TIMEOUT | The request timed out. |
500 | INTERNAL_ERROR | Something went wrong. Please send a note to your Nova Credit Representative with additional details so we can investigate. |
Changelog
We're always working to improve the Nova Credit platform! Here's a snapshot of API features we're shipping and bugs we're squashing.
Changelog History
August 2025
- Added
reportType
to webhooks - Added explicit "current" callout to payroll
pay_period_start
andpay_period_end
fields - Added USA_ARGYLE sandbox testing documentation with 9 test user profiles for employment verification testing
July 2025
- Updated
income.financial_accounts[]
:- Added
primary_account_detected
andjob_irregularity_risk
fields and descriptions
- Added
- Created job_irregularity_risk table
- Updated Visit substatuses:
- Added separate descriptions for
ACCOUNT_TOO_NEW
,NO_RECENT_USABLE_INFORMATION
andNO_USABLE_INCOME_INFORMATION
substatuses based on different income model suite versions.
- Added separate descriptions for
- Added
/connect/income-navigator/v2/files
endpoint - Updated
Sandbox Environment
section to make test inputs more clear. - Added MX as a bank connection partner and
USA_MX
as a validsource_id
- Added
revised_report_values
to income - Added example reports with
revised_report_values
to Report Examples - Added income.financial_accounts[].inflows
- Added income.financial_accounts[].matched_income_sources
June 2025
- Fixed bug where
/connect/income-navigator/v2/files/<filepath>
was returning a 400 instead of 404 when a file was not found - Fixed bug where some endpoints, when returning a non-200 status code, were returning a
terminated
field as a string instead of a boolean
May 2025
- Updated Visit statuses:
- Updated documentation to include
INVITED
- Added new Visit status
INITIALIZED
for when/connect/initialized
is called - Updated the logic for when a Visit status is set to
EXPIRED
: in addition to being set 72 hours after the widget is initially opened, if the widget is never opened it will expire 72 hours after the invite was sent or the initialization endpoint was called
- Updated documentation to include
April 2025
- Update Report Examples - Payroll to fix
identities.matching
March 2025
- Added
nova_report_revision
to themeta
node - Added
REGENERATED_VISIT
webhook type for regenerated reports - Marked
income.payroll[].statements[].net_total_earnings_amount_ytd
as can benull
- Fixed bug where
income.summary
fields were returningnull
values when they should be returning0
- Fixed bug where if
identities[].full_name
from a supplier isnull
, we were not returning a properidentities[].matching.full_name
node for theCONSUMER_INPUT
source. Going forward, if thefull_name
from the supplier isnull
, then it will be part of theunmatched_sources
. - Fixed bug where multiple paystub objects were being returned in
income.paystubs[]
, now returns the most recent paystub if there are multiple.
February 2025
- Updates to
employment[]
:- Marked fields that can be
null
:source_record_id
,employer_name
,employer_address_line_1
,employer_address_line_2
,employer_city
,employer_state
,employment_type
,employment_status
,job_title
- Marked fields that can be
- Updates to
income.paystubs[]
:- Marked fields that can be
null
:employee_name
,employee_address_line_1
,employee_address_line_2
,employee_city
,employee_state
,employee_zip
,pay_period_start
,pay_period_end
,pay_date
,pay_frequency
,paystub_provider
,hire_date
,net_total_earnings_amount_current
,net_total_earnings_amount_ytd
,gross_total_earnings_amount_current
,gross_total_earnings_amount_ytd
,regular_pay_earnings_amount_current
,regular_pay_earnings_amount_ytd
,bonus_earnings_amount_current
,bonus_earnings_amount_ytd
,overtime_earnings_amount_current
,overtime_earnings_amount_ytd
,commission_earnings_amount_current
,commission_earnings_amount_ytd
,paid_time_off_earnings_amount_current
,paid_time_off_earnings_amount_ytd
,vacation_earnings_amount_current
,vacation_earnings_amount_ytd
,paid_time_off_deductions_amount_current
,paid_time_off_deductions_amount_ytd
,vacation_deductions_amount_current
,vacation_deductions_amount_ytd
,medicare_tax_deductions_amount_current
,medicare_tax_deductions_amount_ytd
,social_security_deductions_amount_current
,social_security_deductions_amount_ytd
,fica_tax_deductions_amount_current
,fica_tax_deductions_amount_ytd
- Marked
insights
fields that can be null:annual_gross_income
,annual_net_income
- Marked
irregularity_detection
fields that can be null:file_type
,genuine_pdf
- Marked fields that can be
- Updates to
income.payroll[]
:- Marked fields that can be
null
:annual_salary_rate
,pay_period_start
,pay_period_end
- Marked
statements
fields that can benull
:gross_total_earnings_amount_current
,gross_total_earnings_amount_ytd
,net_total_earnings_amount_current
- Marked fields that can be
- Updates to
income.financial_accounts[].matched_income
: Marked all fields can be null - Fixed bug where
identities[].matching.full_name
source for anOCROLUS
source was missing thesource_record_id
- Fixed bug with
identities[].full_name
: If source hasfirst_name
andlast_name
but nofull_name
, we will now populatefull_name
with a concatenatedfirst_name last_name
January 2025
- Added docs for
source_id
type - Fixed doc for
source_type
, replacedCONSUMER_INPUT
withMANUAL
- Updates to
account_details[]
:- Added
source_id
- Removed
addresses[].neighborhood
andaddresses[].district
- Updated
account_type
type: removedCHECKING
,SAVINGS
,MONEY_MARKET
, addedINSTALLMENT
andMORTGAGE
- Marked fields that can be
null
:owner_full_name
,institution_name
,account_type
,date_opened
,truncated_account_number
,responsibility
,current_balance
- Marked
addresses[]
fields that can be null:street
,city
,zipcode
,state
- Marked
- Added
- Updates to
identities[]
:- Removed
middle_name
- Marked fields that can be
null
:source_record_id
,first_name
,last_name
,full_name
- Removed
December 2024
- Added Nova Product Configuration via API
- Updated
irregularity_detection
to match the updated (v3) fraud schema - Updated sample reports to have correct matching fields
- Removed
income.payroll[].annual_income
- Removed
income.payroll[].statements[].source_id
- Updated
irregularity_detection
to match the updated (v3) fraud schema - Added
source_record_id
field to employment and identities node
November 2024
- Added
external_id
to report meta
October 2024
- Documentation created
Changes from v1
to v2
These are the changes from the Cash Atlas V1 Docs.
Additions/Modifications
- Created an
account_details
node which includes data from the oldbank_transactions[].account_details
node- Does not include
oldest_transaction_date
,routing_number
,full_account_number
,addresses[].neighborhood
, andaddresses[].district
- Does not include
- Added
income.summary
node - Numeric
income.paystub[]
data type changed from "String" to "Float". - Added
ERROR
+INVALID_PREFILL_*
substatuses - Updated name matching logic in
identities
node -matching
will only be included on identities that have asource_id
ofCONSUMER_INPUT
Removals
- Removed
identities[].middle_name
- Removed
identities[].other_names
- Removed
identities[].telephones
- Removed
bank_transactions[]
node - Removed
expenses[]
node - Removed
income.financial_accounts[].confidence_score_recent
- Removed
income.financial_accounts[].confidence_score_annual
- Removed
income.financial_accounts[].matched_income.confidence_score
- Removed
income.financial_accounts[].history[].confidence_score
- Removed
income.payroll[].annual_income
- Removed
income.payroll[].statements[].source_id
- Removed
income.paystubs[].regular_hours_earnings_current
- Removed
income.paystubs[].regular_rate_earnings_current
- Removed
income.paystubs[].commission_hours_earnings_current
- Removed
income.paystubs[].commission_rate_earnings_current
- Removed
income.paystubs[].overtime_hours_earnings_current
- Removed
income.paystubs[].overtime_rate_earnings_current
- Removed
income.paystubs[].bonus_hours_earnings_current
- Removed
income.paystubs[].bonus_rate_earnings_current
- Removed
income.paystubs[].paid_time_off_hours_earnings_current
- Removed
income.paystubs[].paid_time_off_rate_earnings_current
- Removed
income.paystubs[].vacation_hours_earnings_current
- Removed
income.paystubs[].vacation_rate_earnings_current
- Removed
income.paystubs[].annual_salary_rate
- Removed
income.paystubs[].insights.insights_type
- Removed
income.paystubs[].insights.insights_version
- Removed
income.paystubs[].insights.annual_earnings_insight
- Removed
metrics[]
node - Removed
attributes[]
node - Removed
adverse_action_codes[]
node