Build Your Own Experience
What it might look like to combine Nexus and the Payitoff API to power custom experiences in your app.
The most common scenario you'll encounter while trying to help borrowers take control of their student loans looks like this:
- A single Borrower
- tens of thousands of dollars (or more!) in student loan debt
- currently on a Standard or Graduated Repayment Plan
- current payment is a significant chunk of their monthly income
- wants to switch to an Income-Driven Repayment Plan
Add Nexus to Your App
Start integrating Payitoff in your product(s) by adding Nexus to your app or page.
Adding the Nexus script
tag
script
tagYou must include the Nexus script
tag in your app's markup. Where you place it in your markup is up to you, of course, but you must ensure it is included and loaded before any event handlers are triggered by your Borrowers
as they interact with your product(s).
<script src="https://payitoff-cdn.io/sandbox/nexus/js/v1"></script>
Integration begins in the Payitoff Sandbox
For local development, staging, and testing environments, you'll want to include the sandbox version of Nexus.
Payitoff's Sandbox is your development playground—it will never connect to live Servicer websites, it won't submit real Enrollment Requests, it always returns dummy data where necessary, and you'll use a Sandbox Nexus Key that only works in our Sandbox environment.
Don't have your Nexus key or API key?
Please contact [email protected] and we'll get that sorted.
Create Your First Borrower
Every Nexus session is Borrower
-specific, so we'll use the Create Borrowers API endpoint to make your first API call and create your first Borrower
.
# Base Borrowers URL
URL = "https://payitoff-sandbox.io/api/v1/borrowers"
headers = {"Authorization": "Bearer LIVELONGANDPROSPER"}
payload = {
"borrower": {
"first_name": "James",
"last_name": "Kirk"
}
}
response = request("POST", URL, json=payload, headers=headers)
# Inspect new Borrower from response & save to your database
Borrowers have
id
anduuid
valuesEvery
Borrower
created via API will have anid
anduuid
. You should save both values in your systems.When calling API endpoints,
id
anduuid
are largely interchangeable in v1.0.0, and you'll typically see examples in API v1 documentation usingid
values. However, new API endpoints, and Nexus itself, expect to receive a Payitoff UUID when you make calls with our identifiers.
Initialize Nexus
With your first Borrower
created, your Nexus Key, and the Nexus script tag in your page, you can now initialize Nexus in your app. Nexus works on behalf of your Borrowers
to enable linking every Servicer they have relationships with, creating Enrollment Requests, and more in the future. You should plan your integration with Nexus accordingly—the instantiated Nexus object can only operate on a single Borrower
at a time.
let widget = Nexus({
nexus_key: 'GIVINGHERALLSHESGOT',
borrower: '72edfd83-eca2-4383-a015-ff7a230504c2'
})
Use a Payitoff UUID or Your Own Borrower ID
If the
borrower
identifier you supply doesn't look like a validUUID
from our system, or noBorrower
is found, we'll look up aBorrower
using theborrower
value as an external identifier. We manage this internally, but any value you supply that doesn't match our ownUUID
s will result in either fetching or creating aBorrower
with yourborrower
value as their external ID. Find out more details in our Nexus initialization docs.
Use Nexus to link servicer accounts
The first major step for learning more about your Borrower
is to have them link all of their Servicers
. Most Borrowers
only have one Servicer
, but there are still many Borrowers
who have relationships with multiple Servicers
—for example, a Borrower
whose undergraduate loans are with one Servicer
, but their graduate loans are handled by a different Servicer
. Nexus makes it easy for your Borrower
to choose all of the Servicers
they pay monthly and connect their accounts so we can collect the most accurate information about their Loan Portfolio.
A brief overview of Nexus workflows
Nexus currently offers three workflows— link
, assess
, and enroll
. Learn more about each workflow on the main Nexus doc page.
Every Nexus workflow allows you to provide two callbacks—onSuccess
and onExit
. The onExit
callback will be executed whenever your Borrower
cancels the workflow or if a system error is encountered. The onSuccess
callback will be executed whenever your Borrower
successfully completes the workflow.
Invoke Nexus.link
Nexus.link
With Nexus initialized in your app, you'll want to invoke the Nexus.link
workflow to trigger displaying Nexus to your users so they can link all of the Servicers
with whom they have accounts.
// Assuming you have a button your Borrower can click to link Servicers
let linkButton = document.querySelector('#nexus-link-button')
// Attach click handler to invoke Nexus.link
linkButton.addEventListener('click', e => {
Nexus.link({
// the function to call when borrower is done
onSuccess: linkSuccess,
// the function to call when borrower quits or error occurs
onExit: linkExit
})
})
Nexus in Sandbox never connects to real Servicers
Keep in mind that Nexus will never connect to real Servicer sites when in Sandbox. Nexus will be fully operational, provide different authentication experiences, and return dummy data to build out
Borrowers
and their loan portfolios.
Simulate specific experiences when linking Servicers
Servicers
It is possible to simulate different authentication experiences during development when using Nexus in Sandbox.
Default Nexus Sandbox experience is to login with no challenge
The default Nexus experience in Sandbox is to authenticate a
Borrower
without a challenge question. This means you can use any unreserved username and password and Nexus will accept it. See more authentication scenarios in ourNexus.link
doc.
Update Borrower info with API
So, your Borrower
has linked their Servicer
(s), and it's time to move forward with providing an Assessment of their Repayment Options and preparing to create Enrollment Requests.
Earlier, in Step 2, you created your first Borrower
with only a first_name
and last_name
. When your Borrower
links their Servicer
(s) via Nexus, we collect more information about them and their Loan Portfolio, but you'll still need to provide a few key pieces of information about your Borrower
to perform an Assessment:
agi
— their Adjusted Gross Incomefiling_status
— their Tax Filing Statusfamily_size
— the Family Size claimed on their taxesstate_of_residence
— the state in which they reside
We must have at least these 4 pieces of information to determine eligibility and calculate Repayment Options, so let's update our Borrower with the Update Borrower API endpoint.
# Borrower base URL
URL = "https://payitoff-sandbox.io/api/v1/borrowers/{id}"
# Fetch your borrower from your database with your own id values
borrower = Borrowers.get(123)
# Interpolate saved `payitoff_id` into URL
url = URL.format(id=borrower.payitoff_id)
headers = {"Authorization": "Bearer LIVELONGANDPROSPER"}
payload = {
"borrower": {
"agi": 35000,
"filing_status": "single",
"family_size": 1,
"state_of_residence": "NY"
}
}
response = request("PUT", url, json=payload, headers=headers)
# Inspect updated Borrower from response
Fetch Repayment Options and Show Assessment
An Assessment is helpful to your Borrowers
because it allows them to compare the financial impact of Income-Driven Repayment Plans for which they're eligible to their current repayment situation.
Repayment Options are the foundation of presenting an Assessment to your Borrower
. With your Borrower
successfully updated, you're ready to fetch available Repayment Options from the Repayment Options API endpoint.
# Repayment Options URL
URL = "https://partners.payitoff-sandbox.io/api/v1/borrowers/{id}/repayment_options"
# Fetch your borrower from your database with your own id values
borrower = Borrowers.get(123)
# Interpolate saved `payitoff_id` into URL
url = URL.format(id=borrower.payitoff_id)
headers = {"Authorization": "Bearer LIVELONGANDPROSPER"}
response = request("GET", url, headers=headers)
# Inspect Repayment Options from response
Repayment Options API provides all you need for an Assessment
Your
Borrower
will want to compare Income-Driven Repayment Plans to the financial impact of their current plan(s). The Repayment Options API endpoint makes this easy by returning anoriginal
object, which provides a summary of their current Repayment Plan, as well as arepayment_options
array with the details of available options they may or may not be eligible for.
A quick look at original
Loan details
original
Loan detailsThe Repayment Options API endpoint returns a high-level summary of the financial impact of your Borrower
's current Repayment Plan. When building your own Assessment experience, original
provides all the relevant details you'll want to compare to each available Repayment Plan.
{
amount_forgiven: 0.00,
estimated_tax_liability: 0.00,
final_monthly_payment: 22.30,
monthly_payment: 730.00,
number_of_payments: 165,
outstanding_interest: 3496.00,
outstanding_principal: 72597.00,
total_cost: 95699.98,
total_paid: 95699.98
}
A quick look at a Repayment Option
The Repayment Options API endpoint also returns a repayment_options
array, providing details on available Repayment Plans, whether or not your Borrower
is eligible for the plan, and more for you to show your Borrower
how each plan impacts their current financial picture, as well as their future goals.
{
action_items: [],
amount_forgiven: 0.00,
annual_snapshots: [],
eligible_loans: [
// all loans eligible for this Repayment Option
],
estimated_tax_liability: 0.00,
final_monthly_payment: 412.82,
ineligible_loans: [
// any loans ineligible for this Repayment Option
],
ineligible_reasons: [],
name: Extended Fixed,
number_of_payments: 307,
pslf_eligible: false,
repayment_plan: {
description: "Extended Fixed Repayment Plan",
idr: false,
name: "Extended",
type: "extended"
},
scheduled_monthly_payment: 412.82,
starting_monthly_payment: 412.82,
total_cost: 123846.72,
total_paid: 123846.72
}
Your Borrowers won't be eligible for every Repayment Option
Available Repayment Options have their own eligibility rules, and you should expect your
Borrower
won't be eligible for every available Repayment Plan. When this is the case, you'll find thatineligible_loans
will not be an empty array. You will also find details on why yourBorrower
is ineligible for a given Repayment Option in theineligible_reasons
array. If bothineligible_loans
andineligible_reasons
are empty arrays, andeligible_loans
is a non-empty array, you can trust that the Repayment Option is available for yourBorrower
to choose.
Understand total_paid
vs total_cost
total_paid
vs total_cost
When presenting eligible Repayment Options to your Borrower
, you'll likely want to draw their attention to understanding and evaluating the difference between total_paid
and total_cost
across their available options.
total_paid
reflects monthly payments only
total_paid
reflects monthly payments onlyThe total_paid
property provides the sum of all monthly payments a Borrower
will make on each of their loan's over the life of a Repayment Plan.
total_cost
is the true bottom line expense
total_cost
is the true bottom line expenseWith Income-Driven Repayment plans, there is sometimes a tax bomb at the end of the repayment term—any outstanding balance that is forgiven will be treated and assessed to the Borrower
as taxable income. This can be found in the Repayment Option details in the amount_forgiven
property. If amount_forgiven
is non-zero, you will want to ensure your Borrower
understands there could be a tax bomb by presenting the amount provided in the estimated_tax_liability
property. If estimated_tax_liability
is non-zero, then the Repayment Option includes a forgiven amount that will be taxed as income. In this scenario, total_cost
provides the sum of total_paid
(all monthly payments over the repayment term) plus the estimated_tax_liability
.
In other words, total_cost
is the bottom line amount your Borrower
will pay out-of-pocket to dispense of their loan on a given Repayment Plan.
Use Nexus to create an Enrollment Request
Having presented an Assessment to your Borrower
, they will likely find a new Repayment Option that is better than their current plan. Your Assessment experience should allow your Borrower
to select a better plan with a button, link, or some kind of UI control.
Once your Borrower
has selected the Repayment Plan they would like to enroll in, it's time to let Nexus walk them through creating Enrollment Requests that will be submitted to their Servicer
(s).
// Assuming you have a button your Borrower can click to Enroll
let nexusButton = document.querySelector('#nexus-button')
// Attach event listener to invoke Nexus.enroll
nexusButton.addEventListener('click', e => {
Nexus.enroll({
// chosen `repayment_plan.type` from Repayment Option
plan: 'repaye',
onSuccess: function(result) {
// Everything went well
// Congratulate your Borrower on submitting their Enrollment Request
// The `result` object will provide submission details
console.log(result)
},
onExit: function(result) {
switch (result.status) {
case "incomplete":
// User quit the widget.
// Maybe save that they quit so you can prompt them to finish later.
break;
case "illegal":
// You asked to perform a workflow your borrower isn't ready for.
break;
case "error":
// You supplied an invalid Nexus key and/or Borrower UUID,
// or an error occurred in Nexus/Payitoff.
break;
}
}
})
})
A quick look at a Nexus.enroll
response
Nexus.enroll
responseWhen your Borrower
successfully submits their Enrollment Request to change plans, Nexus will execute your onSuccess
callback, providing it with a JSON response that provides submission details you can store and show your Borrower
:
{
result:{
enrollment:{
created_at: "2021-01-27T19:30:01.588745Z",
estimated_approval_date: "2021-03-24",
id: 49,
repayment_plan:{
description: "Revised Pay As You Earn Repayment Plan",
type: "repaye"
},
status:{
updated_at: "2021-01-27T19:30:01.589333Z",
description: "Submission in Progress",
type: "pending"
}
}
},
submitted: true,
success: true
}
Key Enrollment response properties
Whenever you submit an Enrollment Request (via Nexus or our API), there are a few fields worth paying attention to.
We recommend you save the
Enrollment.id
value returned in the submission response. This will help you get more details and check its status with subsequent requests to our API.Your
Borrower
likely wants to have some idea of when they can expect to know more about their submitted Enrollment Requests. We recommend showing yourBorrower
theestimated_approval_date
from the submission response, as this can help set their expectations for how long the Enrollment and Repayment Plan-changing process can take.To check the status of submitted Enrollment Requests after they are created, use our API and the
Enrollment.id
. You'll want to check thestatus
object in the response, particularly thestatus.description
andstatus.type
property to update your own records and share the current status with yourBorrower
. Thestatus.updated_at
property tells you when the last status update occurred.
Congratulations!
That's it! You've successfully integrated Payitoff into your tools for the most common use case. To recap, we have completed the following steps:
- Added Nexus to your application
- Created your first
Borrower
- Saved Payitoff's
Borrower.id
andBorrower.uuid
values on your localBorrower
record for later usage - Used Nexus to connect to one or more Servicers as a
Borrower
- Updated your
Borrower
withagi
,filing_status
,family_size
, andstate_of_residence
- Retrieved Repayment Options
- Presented them to your
Borrower
- Chose a Repayment Option
- Used Nexus to create an Enrollment Request for the chosen Option
Next Steps
With your first integration out of the way, check out our other guides to better understand Nexus, our API, advanced topics, best practices, and more.
Updated over 1 year ago