Bulk Import Interface

Connecting

SFTP access must be set up for a lender to use this interface.

RLS will provide the host (domain) and login credentials to use.

How It Works

A scheduled job runs each hour looking for new files to process in a pickup directory. The status of the imports (how many succeeded, per-record failure messages) are written to an results directory. Files finished processing will be moved to a processed directory. The specifics are further explained below:

Home Directory Structure

Path: {environment}/import/{locations}

Folder Hierarchy

Example: sandbox/import/pickup

Environments

Locations

Explanations

Divisions

If you are a lender with a single division, you can ignore division-related fields. Those fields are only for lenders with multiple divisions.

File Formats

Examples / Testing the Process

The example provided inputs should not be used as-is to test the import process. First, customize them with your own values, especially the email addresses (see Email Values for more of an explanation).

Data and Field Length Restrictions

  1. Please only provide RLS with new or changed records in the provided files. Sending over the entire dataset each time, especially if it is large, may result in slow import times and degraded performance. RLS may be required to delay or temporarily disable import operations if they are adversely affecting the system. Note: It is fine to provide a large data set for the initial / first import, so all the existing data is loaded into the system.

  2. Please trim extra whitespace before sending fields. If a field is String(10) and the value is "IniTech", supply that instead of "IniTech ".

  3. Sending data that is too long may result in truncation or failure to import record(s). The exact behavior of overly long data per field is undefined (do it at your own risk, behavior may change in future).

Modes

Each record has a mode property that indicates what operation should be performed:

ThreadId Values

Unless you are using the API, you will not know what the RLS thread identifiers for records are. You should use the ExternalId/IdNumber/LoanNumber fields instead. The exception to this is divisions, which have a lookup file to pull from.

ExternalId Values

These must be unique across broker accounts, borrowers, and employees. An employee and borrower / broker account cannot have the same External Id. If you need to, you can place a prefix before the value, if you would otherwise have conflicts from the source system sending the data.

Email Values

Per the current system design, all account-type records must have system-wide (RLS) unique email addresses. This affects Create and Update operations against Brokers, Borrowers, and Employees. Only borrowers are permitted to have a duplicate email addresses on Create operations (and that's strictly for borrowers, so if a broker is already using the email, the borrower operation will still fail).

A future system change will add more flexibility with how email addresses work, but this restriction is not removable for now.

Differences with the API

  1. No access token is necessary, as the SFTP login credentials are used instead.

  2. Inquiry mechanisms (get, search, etc.) do not currently exist. This interface exists for writing bulk data to RLS.

  3. There is no support currently for uploading documents to loans, or to bulk rename existing uploads.

Lookup Files

Lookup files are updated at the same frequency that pickup files are processed.

These are provided as both CSV (.csv) and JSON (.json), unless otherwise stated.

Lookup: Divisions

Reminder: Changes to division editable names will not be immediately reflected in this file.

Field Type Description
DivisionThreadId String(32) The unique division identifier.
SystemName String(64) The system name of the division. This value does not change.
EditableName String(200) The user-editable name of the division.

Lookup: Positions

This list will only contain positions that are enabled in lender management.

Field Type Description
DivisionThreadId String(32) The division thread identifier this position is tied to.
Name String(50) Name of the position.

Lookup: Loan Purposes

Field Type Description
Id Integer Unique identifier.
Name String(50) Name / label.

Lookup: Loan Occupancies

Field Type Description
Id Integer Unique identifier.
Name String(50) Name / label.

Lookup: Loan Statuses

Field Type Description
Id Integer Unique identifier.
Name String(50) Name / label.

Lookup: Loan Types

Field Type Description
Id Integer Unique identifier.
Name String(50) Name / label.

Pickup Files

All files start with a prefix indicating what type of data they contain. They are followed by a timestamp and file extension (e.g. borrowers.json).

These files are all JSON formatted, and contain arrays of records (enclosed in []). Example:

[
    { "Id": 1, "Name": "Example A" },
    { "Id": 2, "Name": "Example B" }
]

Filenames

Order of Processing

Files are not processed in alphabetical order, but by order of dependency:

  1. employees.json

  2. borrowers.json

  3. brokers.json

  4. broker_accounts.json

  5. loans.json

  6. loan_positions.json

  7. loan_borrowers.json

  8. loan_brokers.json

Fields

These are the fields for the files mentioned above. Fields with special behavior are denoted below the tables. Some fields have a maximum length, which is included after the data type. Recommended fields are not strictly required, but should be provided when possible.

Null optional fields do not have to be supplied in the JSON, but can be.

Treat field names as case-sensitive.

Fields: Borrowers

For update operations, you can exclude fields that are not being updated.

Field Type Required Description
Mode String(6) Yes "create" or "update".
ExternalId String(200) Special(Id) A unique identifier used by the lender to refer to this record.
ThreadId String(32) Special(Id) The RLS identifier used by the lender to refer to this record.
FirstName String(200) No The first name.
LastName String(200) No The last name.
MiddleInit String(20) No The middle initials.
NameSuffix String(50) No A suffix used after the name (Dr., Jr., III)
Email String(200) Recommended The email address used by the borrower.
Important: This must be unique!
Address1 String(200) No The mailing or physical address of the borrower.
Address2 String(200) No The second line of the physical/mailing address.
City String(100) No The name of the city.
StateCode String(2) No The two-letter state abbreviation.
ZipCode String(10) No The 5 digit ZIP code.
PhonePrimary String(10) No The digits of the primary phone number.
PhoneSecondary String(10) No The digits of the secondary phone number.

Special Borrower Requirements

Example: Borrower Record

[
  {
    "Mode": "create",
    "ExternalId": "Borrower20231219A",
    "FirstName": "Example",
    "MiddleInit": "",
    "LastName": "Borrower",
    "NameSuffix": "Jr.",
    "Email": "Sample20231219a@borrower.test",
    "Address1": "123 Elm",
    "Address2": "Suite C",
    "City": "Dodge City",
    "StateCode": "KS",
    "ZipCode": "67801",
    "PhonePrimary": "5555555123",
    "PhoneSecondary": null
  }
]

Fields: Brokers

For update operations, you can exclude fields that are not being updated.

Creating a new Broker automatically creates a Broker Account and associates it with the Broker as it's owner.

Field Type Required Description
Mode String(6) Yes "create" or "update".
IdNumber String(64) Special(Id) A unique identifier used by the lender to refer to this record.
Warning: This differs from other records, which use ExternalId instead.
ThreadId String(32) Special(Id) The RLS identifier used by the lender to refer to this record.
BrokerDivisionThreadIds Array of
String(32)
Special(Division) A list of division identifiers. This controls which divisions this brokerage is available for.
Email String(200) Recommended The email address of the brokerage contact.
NmlsNumber String(64) No The NMLS number assigned to the brokerage.
CompanyName String(200) No The name of the brokerage company.
OwnerName String(500) No The full name of the owner for the brokerage.
PhoneNumber String(200) No The digits of the brokerage contact phone number.
WebsiteUrl String(2000) No The website of the brokerage. Please prefix this value with https:// or http://.
Address1 String(200) No The mailing or physical address of the broker.
Address2 String(200) No The second line of the physical/mailing address.
City String(100) No The name of the city.
StateCode String(2) No The two-letter state abbreviation.
ZipCode String(10) No The 5 digit ZIP code.
Contacts Array of
BrokerAccountPositionPair
No A list of zero or more brokerage contacts.

Special Broker Account Requirements

Sub-Field Type: BrokerAccountPositionPair

Field Type Required Description
Mode String(50) Yes "add" or "delete". If it already exists, add is ignored.
Account_ThreadId String(6) Special(Id) Broker account thread identifier.
Account_ExternalId String(200) Special(Id) Broker account external identifier.
PositionName String(32) Yes Broker-specific (unrelated to lender positions). May be one of: "Owner", "Loan Officer", "Processor".

Example: Broker Record

[
  {
    "Mode": "create",
    "IdNumber": "23121901",
    "BrokerDivisionThreadIds": ["0123456789abcdef0123456789abcdeff","ffedcba9876543210fedcba9876543210"],
    "Email": "Example20231219A@broker.test",
    "NMLSNumber": "20231219",
    "CompanyName": "Acme Broker",
    "OwnerName": "Thomas Fakeman",
    "PhoneNumber": "5555554545",
    "WebsiteUrl": "https://www.acme-broker.test",
    "Address1": "234 Cedar",
    "Address2": "",
    "City": "Olathe",
    "StateCode": "KS",
    "ZipCode": "66061",
    "Contacts": [
      {
        "Mode": "add",
        "Account_ExternalId": "LoanOfficerBrokerAcct20231219A",
        "PositionName": "loan officer"
      }
    ]
  }
]

Fields: Broker Accounts

For update operations, you can exclude fields that are not being updated.

Field Type Required Description
Mode String(6) Yes "create" or "update".
ExternalId String(200) Special(Id) A unique identifier used by the lender to refer to this record.
ThreadId String(32) Special(Id) The RLS identifier used by the lender to refer to this record.
FirstName String(200) No The first name.
LastName String(200) No The last name.
MiddleInit String(20) No The middle initials.
NameSuffix String(50) No A suffix used after the name (Dr., Jr., III)
Email String(200) Recommended The email address used by the broker account.
Important: This must be unique!
Address1 String(200) No The mailing or physical address of the broker account.
Address2 String(200) No The second line of the physical/mailing address.
City String(100) No The name of the city.
StateCode String(2) No The two-letter state abbreviation.
ZipCode String(10) No The 5 digit ZIP code.
PhonePrimary String(10) No The digits of the primary phone number.
PhoneSecondary String(10) No The digits of the secondary phone number.

Special Broker Account Requirements

Example: Broker Account Record

[
  {
    "Mode": "update",
    "ExternalId": "BrokerAcct20231219A",
    "FirstName": "Sally",
    "MiddleInit": "S",
    "LastName": "Brokerson",
    "NameSuffix": null,
    "Email": "Sample20231219a@broker.test",
    "Address1": "5544 E Market Ln",
    "Address2": "Suite C",
    "City": "Ponca City",
    "StateCode": "OK",
    "ZipCode": "74601",
    "PhonePrimary": "5555555009",
    "PhoneSecondary": "5555555008"
  }
]

Fields: Employees

For update operations, you can exclude fields that are not being updated.

Field Type Required Description
Mode String(6) Yes "create" or "update".
ExternalId String(200) Special(Id) A unique identifier used by the lender to refer to this record.
ThreadId String(32) Special(Id) The RLS identifier used by the lender to refer to this record.
DivisionThreadIds Array of
String(32)
Special(Division) A list of division identifiers. This controls which loans an employee has access to.
FirstName String(200) No The first name.
LastName String(200) No The last name.
MiddleInit String(20) No The middle initials.
NameSuffix String(50) No A suffix used after the name (Dr., Jr., III)
Email String(200) Recommended The email address used by the lender employee.
Important: This must be unique!
Address1 String(200) No The mailing or physical address of the employee.
Address2 String(200) No The second line of the physical/mailing address.
City String(100) No The name of the city.
StateCode String(2) No The two-letter state abbreviation.
ZipCode String(10) No The 5 digit ZIP code.
PhonePrimary String(10) No The digits of the primary phone number.
PhoneSecondary String(10) No The digits of the secondary phone number.

Special Employee Requirements

Example: Employee Record

[
  {
    "Mode": "create",
    "DivisionThreadIds": ["11223344556677889900aabbccddeeff"],
    "ExternalId": "Employee20231219A",
    "FirstName": "Some",
    "LastName": "Employee",
    "Email": "20231219a@employee.test",
    "Address1": "456 E Vine St",
    "City": "Gering",
    "StateCode": "NE",
    "ZipCode": "69341",
    "PhonePrimary": "5555555544"
  }
]

Fields: Loans

Field Type Required Description
Mode String(6) Yes "create" or "update".
LoanNumber String(50) Special(Loan) Loan number.
ThreadId String(32) Special(Loan) Loan thread identifier.
DivisionThreadId String(32) Special(Division) The division the loan is tied to.
Address1 String(200) No The physical address of the property.
Address2 String(200) No The second line of the property address.
City String(100) No The name of the city.
StateCode String(2) No The two-letter state abbreviation.
ZipCode String(10) No The 5 digit ZIP code.
LoanTypeId Integer No The loan type identifier. See loan type lookup for available values.
ClosingDate DateTime No The closing date for the loan.
CompletionDate DateTime No The completion date for the loan.
FHACaseNumber String(50) No The FHA case number.
FundedDate DateTime No The loan funded date.
ClosedOutWithInvestor DateTime No The date the loan is closed out with the investor.
FinalTitleUpdateDate DateTime No The final title update date for the loan.
TotalLoanAmount Decimal No The total loan amount.
LoanPurposeId Integer No The loan purpose identifier. See loan purpose lookup for available values.
LoanOccupancyId Integer No The loan occupancy identifier. See loan occupancy lookup for available values.
StructureTypeId Integer No The structure type identifier. See structure type lookup for available values.
AgencyId Integer No The agency identifier. See agency lookup for available values.
BuildTerm String(50) No The build term in months.
LoanStatusId Integer No The loan status identifier. See loan type status lookup for available values.
WorkOrderDate DateTime No The work date date for the loan.
SorDate DateTime No The SOR (Statement of Repairs) date for the loan.
EstCompletionDate DateTime No The estimated loan completion date.
EscrowReasonRepairType String(50) No The reason for repair type (free-form). E.g. "Home Fixer", "Weather"
EscrowFinalAppraisal String(50) No The final appraisal type for the escrow (free-form). Recommended: "As-Is", "Subject To"
EscrowAppraisalMgmtCompany String(200) No Name of the escrow appraisal management company.

Special Loan Requirements

Example: Loan Record


    [
    {
    "Mode": "create",
    "LoanNumber": "LOAN20231219A",
    "DivisionThreadId": "a0b1c2d3e4f5061728394a5b6c7d8e9f",
    "Address1": "8876 SW Wood Ct",
    "City": "Dickinson",
    "StateCode": "ND",
    "ZipCode": "58601",
    "LoanTypeId": 1,
    "ClosingDate": "2023-12-30T00:00:00",
    "CompletionDate": null,
    "FHACaseNumber": "FHA20231219A",
    "FundedDate": "2023-12-20T00:00:00",
    "ClosedOutWithInvestor": null,
    "FinalTitleUpdateDate": null,
    "TotalLoanAmount": 0,
    "LoanPurposeId": 1,
    "LoanOccupancyId": 1,
    "StructureTypeId": 1,
    "AgencyId": 1,
    "BuildTerm": 0,
    "LoanStatusId": 0,
    "WorkOrderDate": null,
    "SORDate": null,
    "EstCompletionDate": null
    }
    ]

Fields: Loan Positions

Field Type Required Description
Mode String(6) Yes "add" or "delete". If it already exists, add is ignored.
Loan_ThreadId String(32) Special(Loan) Loan thread identifier.
Loan_Number String(50) Special(Loan) Loan number.
Account_ThreadId String(32) Special(Account) Account thread identifier.
Account_ExternalId String(200) Special(Account) Account external identifier.
PositionName String(50) Yes Name of position being added/removed. See positions lookup file for valid values.

Special Loan Positions Requirements

Example: Loan Position Record

[
  {
    "Mode": "add",
    "Loan_Number": "LOAN20231219A",
    "Account_ExternalId": "Employee20231219A",
    "PositionName": "AEA"
  }
]

Fields: Loan Borrowers

Field Type Required Description
Mode String(6) Yes "add" or "delete". If it already exists, add is ignored.
Loan_ThreadId String(32) Special(Loan) Loan thread identifier.
Loan_Number String(50) Special(Loan) Loan number.
Account_ThreadId String(32) Special(Account) Account thread identifier.
Account_ExternalId String(200) Special(Account) Account external identifier.

Special Loan Borrower Requirements

Example: Loan Borrower Record

[
  {
    "Mode": "add",
    "Loan_Number": "LOAN20231219A",
    "Account_ExternalId": "Borrower20231219A"
  }
]

Fields: Loan Brokers

Field Type Required Description
Mode String(6) Yes "add" or "delete". If it already exists, the loan officer / additional contacts will be updated.
Loan_ThreadId String(32) Special(Loan) Loan thread identifier.
Loan_Number String(50) Special(Loan) Loan number.
Broker_ThreadId String(32) Special(Broker) Broker thread identifier.
Broker_IdNumber String(64) Special(Broker) Broker identifier.
LoanOfficer_AccountThreadId String(32) Special(LoanOfficer) Broker loan officer account thread identifier. Must be a broker-type account.
LoanOfficer_AccountExternalId String(200) Special(LoanOfficer) Broker loan officer account external identifier. Must be a broker-type account.
AdditionalContacts Array of
BrokerAccountPositionPair
No List of zero or more additional contacts. Do not supply with "delete" mode.

Special Loan Broker Requirements

Sub-Field Type: BrokerAccountPositionPair

Field Type Required Description
Mode String(50) Yes "add" or "delete". If it already exists, add is ignored.
Account_ThreadId String(6) Special(Id) Broker account thread identifier.
Account_ExternalId String(200) Special(Id) Broker account external identifier.
PositionName String(32) Yes Broker-specific (unrelated to lender positions). May be one of: "Owner", "Loan Officer", "Processor".

Example 1: Loan Broker Record Add

[
  {
    "Mode": "add",
    "Loan_Number": "LOAN20231219A",
    "Broker_IdNumber": "23121901",
    "LoanOfficer_AccountExternalId": "BrokerAcct20231219A",
    "AdditionalContacts": [
      {
        "Mode": "add",
        "Account_ExternalId": "BrokerAcct20231219B",
        "PositionName": "Processor"
      }
    ]
  }
]

Example 2: Loan Broker Record Delete

[
  {
    "Mode": "delete",
    "Loan_Number": "LOAN20231219A",
    "Broker_IdNumber": "23121901"
  }
]

Processed Files

The most recently processed file will follow the convention supplied_name.last.ext.

Earlier / older files will follow supplied_name.timestamp.ext.

The timestamp format is "yyyyMMddhhmmssfff". It consists of a 4-digit year, 2-digit month, 2-digit day, 2-digit "military" hour (00-23), 2-digit minute, 2-digit second, and 3 digit millisecond. All these numbers are zero-padded.

Example processed filenames for "borrowers.json":

  1. "borrowers.last.json" (most recent)

  2. "borrowers.20231222070016329.json" (timestamped)

Empty pickup files (0 byte or whitespace only) will be discarded without creating a result file or being copied to the processed directory.

Result Files

The output result file format is uniform, regardless of what type of data was imported.

Field Type Description
Id Integer Bulk load identifier. Unique per each file operation.
PickupName String Name the file was assigned in the pickup directory. Blank unless Source is "SFTP".
ProcessedName String Name of file in the processed directory. Blank unless Source is "SFTP".
Source String Should be "SFTP". Note: Bulk Web API operation uses "API".
StartedAt DateTime When import started.
EndedAt DateTime When import ended/finished.
ErrorMessage String Set if a problem occurs reading/parsing the data. This being non-null indicates the pickup file is malformed or corrupt.
NumCreateSuccess Integer Number of created records successfully processed (create/update modes).
NumUpdateSuccess Integer Number of updated records successfully processed (create/update modes).
NumAddSuccess Integer Number of added records successfully processed (add/delete modes).
NumDeleteSuccess Integer Number of deleted records successfully processed (add/delete modes).
NumCreateSuccess Integer Number of creation failures (create/update modes).
NumUpdateFailure Integer Number of update failures (create/update modes).
NumAddFailure Integer Number of addition failures (add/delete modes).
NumDeleteFailure Integer Number of deletion failures (add/delete modes).
NumModeFailure Integer Number of failures due to use of an unsupported or invalid mode.
Problems Array of 
Problem
List of zero or more problems found when processing the records. If this is empty, no errors or rejections occurred.

Sub-Output Type: Problem

Field Type Description
Index Integer Index of entry in the source/imported list. Starts at 0.
Message String Error or record rejection message.

Example: Output File Contents

{
  "Id": 123,
  "PickupName": "borrowers.json",
  "ProcessedName": "borrowers.202312201300.json",
  "Source": "SFTP",
  "StartedAt": "2023-12-20T02:30:00.161Z",
  "EndedAt": "2023-12-20T02:30:02.770Z",
  "ErrorMessage": null,
  "NumCreateSuccess": 20,
  "NumUpdateSuccess": 2,
  "NumAddSuccess": 0,
  "NumDeleteSuccess": 0,
  "NumCreateFailure": 0,
  "NumUpdateFailure": 1,
  "NumAddFailure": 0,
  "NumDeleteFailure": 0,
  "NumModeFailure": 0,
  "Problems": [
    {
      "Index": 1,
      "Message": "No borrower for supplied ExternalId exists."
    }
  ]
}

In the example above, the second entry (Index starts at 0) was an attempted update to a non-existent borrower.

Last Updated 2023-12-22, 4:00 PM CDT.