HomeGuidesAPI Reference

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

You 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://sandbox.payitoff.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 and uuid values

Every Borrower created via API will have an id and uuid. You should save both values in your systems.

When calling API endpoints, id and uuid are largely interchangeable in v1.0.0, and you'll typically see examples in API v1 documentation using id 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({
  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 valid UUID from our system, or no Borrower is found, we'll look up a Borrower using the borrower value as an external identifier. We manage this internally, but any value you supply that doesn't match our own UUIDs will result in either fetching or creating a Borrower with your borrower 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

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 => {
    // 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

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 our Nexus.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 Income
  • filing_status — their Tax Filing Status
  • family_size — the Family Size claimed on their taxes
  • state_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://sandbox.payitoff.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://sandbox.payitoff.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 an original object, which provides a summary of their current Repayment Plan, as well as a repayment_options array with the details of available options they may or may not be eligible for.

A quick look at original Loan details

The 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 that ineligible_loans will not be an empty array. You will also find details on why your Borrower is ineligible for a given Repayment Option in the ineligible_reasons array. If both ineligible_loans and ineligible_reasons are empty arrays, and eligible_loans is a non-empty array, you can trust that the Repayment Option is available for your Borrower to choose.

Understand 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

The 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

With 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 => {
    // 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
    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.
        case "illegal":
          // You asked to perform a workflow your borrower isn't ready for.
        case "error":
          // You supplied an invalid Nexus key and/or Borrower UUID,
          // or an error occurred in Nexus/Payitoff.

A quick look at a Nexus.enroll response

When 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:

      created_at: "2021-01-27T19:30:01.588745Z",
      estimated_approval_date: "2021-03-24",
      id: 49,
        description: "Revised Pay As You Earn Repayment Plan",
        type: "repaye"
        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 your Borrower the estimated_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 the status object in the response, particularly the status.description and status.type property to update your own records and share the current status with your Borrower. The status.updated_at property tells you when the last status update occurred.


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 and Borrower.uuid values on your local Borrower record for later usage
  • Used Nexus to connect to one or more Servicers as a Borrower
  • Updated your Borrower with agi, filing_status, family_size, and state_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.