Expanding Objects
How to expand objects to pull specific information.
Introduction
LoanPro's API is built on REST principles and uses OData concepts to structure information. That information is stored in a JSON format, and the system both accepts and returns information in JSON payloads. Each response you receive from the API includes objects that represent what we call ‘entities’, and they hold specific groups of information. We nest entities within other entities, creating tiers of information akin to Russian nesting dolls. In this article, we'll explain how to expand those objects to extract specific information from them.
How Nested Entities Work
If you're familiar with LoanPro's API, you'll know that most of our API requests use endpoints that act as the parent entity for multiple, nested entities. For example, customer address information is held within a PrimaryAddress
entity, and a loan's collateral information is held with the Collateral
entity. Each of these nested entities, like Collateral and PrimaryAddress
, are assigned their own IDs and are associated with the parent Loans
or Customers
entity.
As mentioned above, this structure of data is a bit similar to how a set of Russian nesting dolls fit together—the entities may store a nested entity that stores another nested entity, with the data they hold becoming more and more granular.
Let's look at customer information as an example. When you send a GET request for customer information, you'll receive a long response that's full of objects that represent each nested entity:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Customers(1183)
{
"d": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Customers(id=1183)",
"type": "Entity.Customer"
},
"PrimaryAddress": {
"__deferred": {
"uri": "Customers(id=1183)/PrimaryAddress"
}
},
"MailAddress": {
"__deferred": {
"uri": "Customers(id=1183)/MailAddress"
}
},
"Employer": {
"__deferred": {
"uri": "Customers(id=1183)/Employer"
}
},
"References": {
"__deferred": {
"uri": "Customers(id=1183)/References"
}
},
"PaymentAccounts": {
"__deferred": {
"uri": "Customers(id=1183)/PaymentAccounts"
}
},
"Phones": {
"__deferred": {
"uri": "Customers(id=1183)/Phones"
}
},
"CustomFieldValues": {
"__deferred": {
"uri": "Customers(id=1183)/CustomFieldValues"
}
},
"Documents": {
"__deferred": {
"uri": "Customers(id=1183)/Documents"
}
},
"CreditScore": {
"__deferred": {
"uri": "Customers(id=1183)/CreditScore"
}
},
"Loans": {
"__deferred": {
"uri": "Customers(id=1183)/Loans"
}
},
"LineOfCredits": {
"__deferred": {
"uri": "Customers(id=1183)/LineOfCredits"
}
},
"SocialProfiles": {
"__deferred": {
"uri": "Customers(id=1183)/SocialProfiles"
}
},
"Notes": {
"__deferred": {
"uri": "Customers(id=1183)/Notes"
}
},
"id": 1183,
"customId": null,
"mcId": 3874462,
"customerType": "customer.type.individual",
"status": "Active",
"firstName": "John",
"lastName": "Doe",
"middleName": null,
"birthDate": "/Date(0)/",
"gender": "customer.gender.male",
"generationCode": "customer.generationCode.none",
"email": "[email protected]",
"ssn": "XXXXX1010",
"driverLicense": null,
"companyName": null,
"contactName": null,
"customerIdType": "customer.idType.ssn",
"customerId": null,
"creditLimit": 0,
"accessUserName": "JohnDoe212",
"active": 1,
"ofacMatch": 0,
"ofacTested": 0,
"saleTransferPii": 1,
"passwordChanged": 0,
"hasAvatar": 0,
"loanRole": null,
"created": "/Date(1632417901)/",
"lastUpdate": "/Date(1677534526)/",
"creditScoreId": 213
}
}
There are multiple objects listed in this response, but the information they store is not displayed by default. To extract that information, you need to make some alterations to your endpoint by either using an $expand
filter or forward slashes.
Using Query Options to Extract Information
OData uses query options to limit or increase the results listed in the response to a request. These expressions are added to the endpoint of a request, and they can do things such as filter information, select specific information, or expand objects. We're going to use OData's $expand
query option to extract information from the objects listed in a response. As an example, let's expand the PrimaryAddress
object to pull the information that it stores:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Customers(1183)?$expand=PrimaryAddress
{
"d": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Customers(id=1183)",
"type": "Entity.Customer"
},
"PrimaryAddress": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Address(id=2554)",
"type": "Entity.Address"
},
"id": 2554,
"address1": "3844 20th Street",
"address2": null,
"city": "San Francisco",
"state": "geo.state.CA",
"zipcode": "94114",
"country": "company.country.usa",
"geoLat": "37.758198521738",
"geoLon": "-122.42684494282",
"created": "/Date(1632417901)/",
"active": 1,
"isVerified": 0,
"isStandardized": 0
},
"MailAddress": {
"__deferred": {
"uri": "Customers(id=1183)/MailAddress"
}
},
"Employer": {
"__deferred": {
"uri": "Customers(id=1183)/Employer"
}
},
"References": {
"__deferred": {
"uri": "Customers(id=1183)/References"
}
},
"PaymentAccounts": {
"__deferred": {
"uri": "Customers(id=1183)/PaymentAccounts"
}
},
"Phones": {
"__deferred": {
"uri": "Customers(id=1183)/Phones"
}
},
"CustomFieldValues": {
"__deferred": {
"uri": "Customers(id=1183)/CustomFieldValues"
}
},
"Documents": {
"__deferred": {
"uri": "Customers(id=1183)/Documents"
}
},
"CreditScore": {
"__deferred": {
"uri": "Customers(id=1183)/CreditScore"
}
},
"Loans": {
"__deferred": {
"uri": "Customers(id=1183)/Loans"
}
},
"LineOfCredits": {
"__deferred": {
"uri": "Customers(id=1183)/LineOfCredits"
}
},
"SocialProfiles": {
"__deferred": {
"uri": "Customers(id=1183)/SocialProfiles"
}
},
"Notes": {
"__deferred": {
"uri": "Customers(id=1183)/Notes"
}
},
"id": 1183,
"customId": null,
"mcId": 3874462,
"customerType": "customer.type.individual",
"status": "Active",
"firstName": "John",
"lastName": "Doe",
"middleName": null,
"birthDate": "/Date(0)/",
"gender": "customer.gender.male",
"generationCode": "customer.generationCode.none",
"email": "[email protected]",
"ssn": "XXXXX1010",
"driverLicense": null,
"companyName": null,
"contactName": null,
"customerIdType": "customer.idType.ssn",
"customerId": null,
"creditLimit": 0,
"accessUserName": "JohnDoe212",
"active": 1,
"ofacMatch": 0,
"ofacTested": 0,
"saleTransferPii": 1,
"passwordChanged": 0,
"hasAvatar": 0,
"loanRole": null,
"created": "/Date(1632417901)/",
"lastUpdate": "/Date(1677534526)/",
"creditScoreId": 213
}
}
As you can see in the response above, we received the list of objects within our response again, but the PrimaryAddress object has been expanded and its information is now displayed. You can expand multiple objects in a single request, too. To do so, add additional object names to your endpoint and separate them each by a comma.
Here's an example:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Loans(9114)?$expand=LoanSetup,Payments,Portfolios,Customers
Expanding Objects Nested Within Objects
You'll notice that some objects contain objects themselves. For example, the Loans
entity holds the Autopays
object which holds the PrimaryPaymentMethod
object. To pull information from an object nested within another object, use an $expand
query option to expand the first object, followed by a forward slash, and then the name of the second object. Here's an example and the response it provides:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Loans(9114)?$expand=Autopays/PrimaryPaymentMethod
{
"d": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Loans(id=9114)",
"type": "Entity.Loan"
},
"Insurance": {
"__deferred": {
"uri": "Loans(id=9114)/Insurance"
}
},
"CustomFieldValues": {
"__deferred": {
"uri": "Loans(id=9114)/CustomFieldValues"
}
},
"ChecklistItemValues": {
"__deferred": {
"uri": "Loans(id=9114)/ChecklistItemValues"
}
},
"Documents": {
"__deferred": {
"uri": "Loans(id=9114)/Documents"
}
},
"Collateral": {
"__deferred": {
"uri": "Loans(id=9114)/Collateral"
}
},
"LoanSettings": {
"__deferred": {
"uri": "Loans(id=9114)/LoanSettings"
}
},
"LoanSetup": {
"__deferred": {
"uri": "Loans(id=9114)/LoanSetup"
}
},
"Notes": {
"__deferred": {
"uri": "Loans(id=9114)/Notes"
}
},
"Promises": {
"__deferred": {
"uri": "Loans(id=9114)/Promises"
}
},
"Bankruptcies": {
"__deferred": {
"uri": "Loans(id=9114)/Bankruptcies"
}
},
"Charges": {
"__deferred": {
"uri": "Loans(id=9114)/Charges"
}
},
"Payments": {
"__deferred": {
"uri": "Loans(id=9114)/Payments"
}
},
"LoanFunding": {
"__deferred": {
"uri": "Loans(id=9114)/LoanFunding"
}
},
"Advancements": {
"__deferred": {
"uri": "Loans(id=9114)/Advancements"
}
},
"Credits": {
"__deferred": {
"uri": "Loans(id=9114)/Credits"
}
},
"DueDateChanges": {
"__deferred": {
"uri": "Loans(id=9114)/DueDateChanges"
}
},
"CurtailmentDates": {
"__deferred": {
"uri": "Loans(id=9114)/CurtailmentDates"
}
},
"StatusArchive": {
"__deferred": {
"uri": "Loans(id=9114)/StatusArchive"
}
},
"Transactions": {
"__deferred": {
"uri": "Loans(id=9114)/Transactions"
}
},
"EscrowCalculatedTx": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowCalculatedTx"
}
},
"ScheduleRolls": {
"__deferred": {
"uri": "Loans(id=9114)/ScheduleRolls"
}
},
"StopInterestDates": {
"__deferred": {
"uri": "Loans(id=9114)/StopInterestDates"
}
},
"APDAdjustments": {
"__deferred": {
"uri": "Loans(id=9114)/APDAdjustments"
}
},
"DPDAdjustments": {
"__deferred": {
"uri": "Loans(id=9114)/DPDAdjustments"
}
},
"InterestAdjustments": {
"__deferred": {
"uri": "Loans(id=9114)/InterestAdjustments"
}
},
"LoanModifications": {
"__deferred": {
"uri": "Loans(id=9114)/LoanModifications"
}
},
"EscrowAdjustments": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowAdjustments"
}
},
"EscrowTransactions": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowTransactions"
}
},
"EscrowSubsetOptions": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowSubsetOptions"
}
},
"EscrowCalculators": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowCalculators"
}
},
"EstimatedDisbursements": {
"__deferred": {
"uri": "Loans(id=9114)/EstimatedDisbursements"
}
},
"Loans": {
"__deferred": {
"uri": "Loans(id=9114)/Loans"
}
},
"LinkedLoanValues": {
"__deferred": {
"uri": "Loans(id=9114)/LinkedLoanValues"
}
},
"LoanChilds": {
"__deferred": {
"uri": "Loans(id=9114)/LoanChilds"
}
},
"RecurrentCharges": {
"__deferred": {
"uri": "Loans(id=9114)/RecurrentCharges"
}
},
"PayNearMeOrders": {
"__deferred": {
"uri": "Loans(id=9114)/PayNearMeOrders"
}
},
"Customers": {
"__deferred": {
"uri": "Loans(id=9114)/Customers"
}
},
"Portfolios": {
"__deferred": {
"uri": "Loans(id=9114)/Portfolios"
}
},
"SubPortfolios": {
"__deferred": {
"uri": "Loans(id=9114)/SubPortfolios"
}
},
"EscrowSubsets": {
"__deferred": {
"uri": "Loans(id=9114)/EscrowSubsets"
}
},
"RuleApplied": {
"__deferred": {
"uri": "Loans(id=9114)/RuleApplied"
}
},
"RuleAppliedLoanSettings": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedLoanSettings"
}
},
"RuleAppliedChargeOff": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedChargeOff"
}
},
"RuleAppliedAPDReset": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedAPDReset"
}
},
"RuleAppliedChecklists": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedChecklists"
}
},
"RuleAppliedChangeDueDates": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedChangeDueDates"
}
},
"RuleAppliedStopInterest": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedStopInterest"
}
},
"RuleAppliedAccountTools": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedAccountTools"
}
},
"RuleAppliedCustomerTools": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedCustomerTools"
}
},
"RuleAppliedAutopay": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedAutopay"
}
},
"RuleAppliedLoanSetup": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedLoanSetup"
}
},
"RuleAppliedBankruptcy": {
"__deferred": {
"uri": "Loans(id=9114)/RuleAppliedBankruptcy"
}
},
"Autopays": {
"results": [
{
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Autopays(id=311)",
"type": "Entity.Autopay"
},
"PrimaryPaymentMethod": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/PaymentAccounts(id=416)",
"type": "Entity.PaymentAccount"
},
"CheckingAccount": {
"__deferred": {
"uri": "PaymentAccounts(id=416)/CheckingAccount"
}
},
"CreditCard": {
"__deferred": {
"uri": "PaymentAccounts(id=416)/CreditCard"
}
},
"id": 416,
"entityId": 1183,
"entityType": "Entity.Customer",
"importId": null,
"isPrimary": 1,
"isSecondary": 0,
"title": "Checking",
"type": "paymentAccount.type.checking",
"creditCardId": null,
"checkingAccountId": 375,
"active": 1,
"visible": 1,
"verify": 0
},
"SecondaryPaymentMethod": {
"__deferred": {
"uri": "Autopays(id=311)/SecondaryPaymentMethod"
}
},
"AdditionalPaymentMethod": {
"__deferred": {
"uri": "Autopays(id=311)/AdditionalPaymentMethod"
}
},
"Loan": {
"__deferred": {
"uri": "Autopays(id=311)/Loan"
}
},
"PaymentType": {
"__deferred": {
"uri": "Autopays(id=311)/PaymentType"
}
},
"TransactionChilds": {
"__deferred": {
"uri": "Autopays(id=311)/TransactionChilds"
}
},
...
(We've shortened the response above to save you from scrolling through thousands of lines.)
Alternatively, you can rearrange the format of your request to shorten your response:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Loans(9114)/Autopays?$expand=PrimaryPaymentMethod
{
"d": {
"results": [
{
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/Autopays(id=311)",
"type": "Entity.Autopay"
},
"PrimaryPaymentMethod": {
"__metadata": {
"uri": "http://loanpro.simnang.com/api/public/api/1/odata.svc/PaymentAccounts(id=416)",
"type": "Entity.PaymentAccount"
},
"CheckingAccount": {
"__deferred": {
"uri": "PaymentAccounts(id=416)/CheckingAccount"
}
},
"CreditCard": {
"__deferred": {
"uri": "PaymentAccounts(id=416)/CreditCard"
}
},
"id": 416,
"entityId": 1183,
"entityType": "Entity.Customer",
"importId": null,
"isPrimary": 1,
"isSecondary": 0,
"title": "Checking",
"type": "paymentAccount.type.checking",
"creditCardId": null,
"checkingAccountId": 375,
"active": 1,
"visible": 1,
"verify": 0
},
"SecondaryPaymentMethod": {
"__deferred": {
"uri": "Autopays(id=311)/SecondaryPaymentMethod"
}
},
"AdditionalPaymentMethod": {
"__deferred": {
"uri": "Autopays(id=311)/AdditionalPaymentMethod"
}
},
"Loan": {
"__deferred": {
"uri": "Autopays(id=311)/Loan"
}
},
"PaymentType": {
"__deferred": {
"uri": "Autopays(id=311)/PaymentType"
}
},
"TransactionChilds": {
"__deferred": {
"uri": "Autopays(id=311)/TransactionChilds"
}
},
"id": 311,
"loanId": 9114,
"name": "API Docs AutoPay",
"type": "autopay.type.single",
"applyDate": "/Date(1675123200)/",
"processDateTime": "/Date(1675180800)/",
"originalProcessDateTime": "/Date(1675180800)/",
"amountType": "autopay.amountType.nextDue",
"amount": 170.71000000000001,
"processCurrent": 1,
"chargeServiceFee": 0,
"retryDays": 0,
"retryCount": 0,
"scheduleNextIfFail": 0,
"postPaymentUpdate": 0,
"recurringFrequency": "autopay.recurringFrequency.monthly",
"recurringPeriods": 1,
"recurringDateOption": "autopay.recurringDate.processDate",
"schedulingType": "autoapay.schedulingType.bankingDayPrior",
"paymentExtraTowards": "payment.extra.periods.next",
"daysInPeriod": null,
"lastDayOfMonthEnabled": 0,
"applyLastDayOfMonthEnabled": 0,
"paymentFee": 0,
"paymentMethodAuthType": "payment.echeckauth.WEB",
"payoffAdjustment": 0,
"chargeOffRecovery": 0,
"mcProcessor": null,
"ccProcessor": 125,
"baProcessor": 129,
"processZeroOrNegativeBalance": 1,
"status": "autopay.status.failed",
"active": 1,
"created": "/Date(1675176212)/",
"lastPaymentExtraTowards": null,
"_applyDateAsString": "2023-01-31"
},
...
Rearranging your request like this will limit your response to only include information stored within the Autopays
object instead of pulling an entire list of objects stored within the Loans entity.
Want to go a layer deeper? Add another forward slash and object name to your request:
GET https://loanpro.simnang.com/api/public/api/1/odata.svc/Loans(9114)/Autopays?$expand=PrimaryPaymentMethod/CheckingAccount
Updated 11 months ago