Origination Data
Complete System Setup with Figure for platform access and Origination Data Requirements before your first production onboard request.
Create Onboard Request
POST /api/onboard creates an onboard request that includes the origination data and files for one or more loans.
| Field | Description |
|---|---|
manifest.loanTape | Origination data for each loan in the request, using your source field names—one JSON object per loan or one CSV row per loan. Send inline as JSON or upload a CSV file. |
manifest.underwritingGuidelines | Underwriting guidelines—the eligibility rules for the product. Every loan in the request should have been originated under these guidelines. One file for the whole request. See Underwriting Guidelines. |
manifest.externalIdKey | Names which loan-tape field holds your loan identifier (for example loanNumber). Keep this field name stable across requests for the same product. |
manifest.loans[].id | Your loan identifier for that entry. Must match the loan tape value for the field named by manifest.externalIdKey. This value is Figure's primary key for the loan—do not change it when correcting or updating an onboarded loan. |
manifest.loans[].data | Loan Participants. Required servicerId and optional originatorId and subservicerId—each holds the Figure Participant ID for the servicer, originator, or subservicer on that loan. See Loan Participants. |
manifest.loans[].files | Loan documents for that loan—closing-package files (such as the signed note) and supporting documents. Each entry has a documentType. See Loan Documents. |
manifest.dataDictionary | Optional Partner Data Dictionary. Descriptions of your field names, types, and meanings. See Partner Data Dictionary. |
After the request is created, the response includes uploadUrls, a map of signed URLs for uploading the files. Upload each named file with PUT to its URL and then submit the request. See Create, Upload, Submit for details on upload URLs, submit, and status.
Sample
POST /api/onboard
{
"name": "2026-10-01_rtl-batch",
"manifest": {
"loanType": "RTL",
"externalIdKey": "loanNumber",
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"originalBalance": 250000,
"ficoScore": 720,
"dscrRatio": 1.25
},
{
"loanNumber": "loan-1002",
"originalBalance": 180000,
"ficoScore": 690,
"dscrRatio": 1.40
}
]
},
"underwritingGuidelines": "rtl-core-program-underwriting-guidelines.json",
"loans": [
{
"id": "loan-1001",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
},
{
"id": "loan-1002",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
}
]
}
}
Loan Tape
loanTape is required. Send it in one of two forms:
- JSON —
source: PAYLOADanddataset to an array of objects, one object per loan. - CSV —
source: CSVandfileset to the CSV file name. Include a header row.
Use the field names and structure from your source system. Do not rename columns to Figure field names. Keeping your source names makes the loan tape easier to compare with your underwriting guidelines and preserves product-specific fields that may not exist in Figure's standard model.
For each loan, the tape should include:
- as many values from the Figure Data Dictionary as you have, under your corresponding source field names
- any origination fields referenced by your underwriting guidelines, even when they are not on the Figure Data Dictionary
- any other origination fields you consider important for the loan, even when they are not on the Figure Data Dictionary
Pick one format for manifest.loanTape. The same source field names and loan rows apply to every option; only how you attach the tape changes.
externalIdKey names the loan-tape field that holds your loan identifier. Each loans[].id must equal that value on the matching row. Send the key you actually use. LOAN_ID is the usual name.
manifest.externalIdKey and manifest.loans[].id (with the matching tape value) are Figure's primary key for the loan on Provenance. Use the same identifier value and the same externalIdKey on every onboard request, merge update, and correction for that loan.
If you change the id value or use a different externalIdKey on a later request, Figure treats it as a new loan and onboards a new asset (NFT) instead of updating the existing loan.
loanType is one of AUTO_LOAN, CONSUMER_UNSECURED, DSCR, SMB, or RTL. Every loan in the request uses that type.
Inline JSON (PAYLOAD)
Include the tape in the create request body. One JSON object per loan, using your source field names. You do not upload a separate loan tape file; uploadUrls will not include a tape file name.
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"originalBalance": 250000,
"ficoScore": 720,
"dscrRatio": 1.25
},
{
"loanNumber": "loan-1002",
"originalBalance": 180000,
"ficoScore": 690,
"dscrRatio": 1.40
}
]
}
CSV File
Upload a .csv file with a header row and one row per loan. In the manifest, set source to CSV and file to the file name you will upload. The create response includes a signed URL for that file.
Example file contents:
loanNumber,originalBalance,ficoScore,dscrRatio
loan-1001,250000,720,1.25
loan-1002,180000,690,1.40
Manifest reference:
"loanTape": {
"source": "CSV",
"file": "loans.csv"
}
The examples above use the same source fields in both formats. For these rows, externalIdKey is loanNumber, so each loans[].id in the create body must match loanNumber on that loan:
"externalIdKey": "loanNumber",
"loanType": "RTL"
Underwriting Guidelines
The underwriting guidelines document contains the eligibility rules used to determine whether an applicant and proposed loan qualify for a loan product. Every loan in the request should have been originated under these guidelines. The rules may include borrower qualifications, credit thresholds, loan limits, collateral requirements, and other product-specific criteria.
Provide the file using manifest.underwritingGuidelines. The value is the file name, not the file contents. Upload the file to the signed URL returned for that name.
- One file containing the guidelines applies to every loan in the request. When loans were originated under different programs, send a separate request for each set of guidelines.
- The guidelines file does not need a Figure-defined format. JSON, non-scanned PDFs, UTF-8 text files (including Markdown), and Word documents are accepted. Scanned PDFs and image files are not supported.
- The AI Validator compares each loan's submitted source data with these rules and returns a validation result. It evaluates only rules for which it has the data needed; when data is missing to evaluate a rule, that rule is skipped.
Name the file in the manifest, then upload its bytes to the signed URL returned for that name:
"underwritingGuidelines": "rtl-core-program-underwriting-guidelines.json"
A JSON file containing the guidelines can represent the rules with your source field names. This excerpt applies to every loan in the request:
{
"product": "RTL",
"rules": [
{ "field": "ficoScore", "minimum": 680 },
{ "field": "dscrRatio", "minimum": 1.2 }
]
}
A PDF containing the same eligibility rules is named the same way:
"underwritingGuidelines": "rtl-core-program-underwriting-guidelines.pdf"
Loan Documents
loans[].files lists loan documents for that loan: items from the closing package and any supporting documents Figure expects for the product. Each entry is a file name, or an object with fileName and documentType. Names must be unique within the loan, and each name is a relative path (note.pdf, not /tmp/note.pdf or ../note.pdf).
Set documentType to a value from the API Reference enum, such as SIGNED_NOTE, CREDIT_REPORT, or SIGNED_CLOSING_PACKAGE. Use USER_UPLOADED_DOC when none of the enum values fit.
Which loan documents are required depends on the product. Confirm that list with Figure Capital Markets during onboarding.
"loans": [
{
"id": "loan-1001",
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
},
{
"id": "loan-1002",
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
}
]
A file name without an explicit type is also accepted. It is stored as UNKNOWN:
"files": ["loan-1001-guaranty.pdf"]
Loan Participants
Each entry in manifest.loans has an id, data, and files. The data object holds Figure Participant IDs for the servicer, originator, and optional subservicer on that loan.
loans[].data.servicerId is required. It is the servicer's Figure Participant ID. Figure provides it during System Setup. When you service the loan yourself, use your organization's Figure Participant ID for that environment.
originatorId is optional and defaults to the Figure Participant ID for the originator tied to your API key. Set it when you onboard on behalf of another originator; see Originator Authorization. subservicerId is optional when a subservicer applies—the subservicer's Figure Participant ID.
Figure authorizes the servicer and originator Figure Participant IDs that your API key may onboard. If create returns 403 or an authorization error for a participant, see Servicer Authorization and Originator Authorization, or email dart-engineering@figure.com.
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111",
"originatorId": "22222222-2222-2222-2222-222222222222",
"subservicerId": "33333333-3333-3333-3333-333333333333"
}
When you are both the originator and the servicer, send only your Figure Participant ID as servicerId:
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
}
Each loan ID must match a loanNumber in the tape. Both loans in this batch use the same servicer:
"loans": [
{
"id": "loan-1001",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" }
]
},
{
"id": "loan-1002",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
}
]
Partner Data Dictionary
Optional manifest.dataDictionary is your Partner Data Dictionary: descriptions of your source fields that help Figure interpret them during mapping. It does not map your columns to Figure field names and does not replace the Figure Data Dictionary or the mapping review.
- CSV — first column is the field name, second column is the description.
- JSON —
source: PAYLOADanddataas a list of single-entry objects, for example{ "originalBalance": "Original loan amount" }.
A CSV dictionary uses the source field name in the first column and the description in the second:
loanNumber,Partner loan identifier
originalBalance,Original loan amount in dollars
ficoScore,Borrower credit score required by the underwriting guidelines
dscrRatio,Debt service coverage ratio required by the underwriting guidelines
"dataDictionary": {
"source": "CSV",
"file": "source-fields.csv"
}
The same descriptions can be sent inline:
"dataDictionary": {
"source": "PAYLOAD",
"data": [
{ "loanNumber": "Partner loan identifier" },
{ "originalBalance": "Original loan amount in dollars" },
{ "ficoScore": "Borrower credit score required by the underwriting guidelines" },
{ "dscrRatio": "Debt service coverage ratio required by the underwriting guidelines" }
]
}
Create, Upload, Submit
The create body names files. It does not contain file bytes.
POST /api/onboardwith the manifest.PUTeach file to the signed URL inuploadUrls. When the loan tape is a file, the map includes that file too. It always includes the file containing the underwriting guidelines, the optional dictionary, and every loan file. An inline JSON tape does not add a tape file touploadUrls.POST /api/onboard/{requestId}to submit. Submit checks that the named files arrived. The AI Validator then compares the uploaded loan tape with the guidelines' eligibility rules (skipping rules it cannot evaluate for lack of data).GET /api/onboard/{requestId}/statusuntilstatusisCompletedorFailed.
Signed URLs expire. Upload and submit before they do.
Do not upload real borrower or customer PII to the test gateway. Use fully synthetic loan packages, or scrub production exports so names, contact details, government identifiers, financial account numbers, and other personal information are removed or replaced before upload. This applies to the loan tape, files containing underwriting guidelines, and loan documents.
{
"name": "2026-10-01_rtl-batch",
"manifest": {
"loanType": "RTL",
"externalIdKey": "loanNumber",
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"originalBalance": 250000,
"ficoScore": 720,
"dscrRatio": 1.25
},
{
"loanNumber": "loan-1002",
"originalBalance": 180000,
"ficoScore": 690,
"dscrRatio": 1.40
}
]
},
"underwritingGuidelines": "rtl-core-program-underwriting-guidelines.json",
"loans": [
{
"id": "loan-1001",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
},
{
"id": "loan-1002",
"data": {
"servicerId": "11111111-1111-1111-1111-111111111111"
},
"files": [
{ "fileName": "credit-report.pdf", "documentType": "CREDIT_REPORT" },
{ "fileName": "signed-deed.pdf", "documentType": "SIGNED_DEED" },
{ "fileName": "appraisal.pdf", "documentType": "APPRAISAL" },
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" },
{ "fileName": "closing-package.pdf", "documentType": "SIGNED_CLOSING_PACKAGE" },
{ "fileName": "w-9.pdf", "documentType": "W_9" }
]
}
]
}
}
Set servicerId to the servicer's Figure Participant ID. Each loans[].id must match loanNumber on the corresponding tape row. One file containing the underwriting guidelines covers both loans.
Create returns a signed URL for every file named in the manifest:
{
"requestId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"name": "2026-10-01_rtl-batch",
"uploadUrls": {
"rtl-core-program-underwriting-guidelines.json": "https://storage.example/rtl-core-program-underwriting-guidelines.json?signature=...",
"loan-1001/credit-report.pdf": "https://storage.example/loan-1001/credit-report.pdf?signature=...",
"loan-1001/signed-deed.pdf": "https://storage.example/loan-1001/signed-deed.pdf?signature=...",
"loan-1001/appraisal.pdf": "https://storage.example/loan-1001/appraisal.pdf?signature=...",
"loan-1001/note.pdf": "https://storage.example/loan-1001/note.pdf?signature=...",
"loan-1001/closing-package.pdf": "https://storage.example/loan-1001/closing-package.pdf?signature=...",
"loan-1001/w-9.pdf": "https://storage.example/loan-1001/w-9.pdf?signature=...",
"loan-1002/credit-report.pdf": "https://storage.example/loan-1002/credit-report.pdf?signature=...",
"loan-1002/signed-deed.pdf": "https://storage.example/loan-1002/signed-deed.pdf?signature=...",
"loan-1002/appraisal.pdf": "https://storage.example/loan-1002/appraisal.pdf?signature=...",
"loan-1002/note.pdf": "https://storage.example/loan-1002/note.pdf?signature=...",
"loan-1002/closing-package.pdf": "https://storage.example/loan-1002/closing-package.pdf?signature=...",
"loan-1002/w-9.pdf": "https://storage.example/loan-1002/w-9.pdf?signature=..."
}
}
Upload each named file with PUT to its signed URL:
PUT https://storage.example/rtl-core-program-underwriting-guidelines.json?signature=...
PUT https://storage.example/loan-1001/credit-report.pdf?signature=...
PUT https://storage.example/loan-1001/signed-deed.pdf?signature=...
PUT https://storage.example/loan-1001/appraisal.pdf?signature=...
PUT https://storage.example/loan-1001/note.pdf?signature=...
PUT https://storage.example/loan-1001/closing-package.pdf?signature=...
PUT https://storage.example/loan-1001/w-9.pdf?signature=...
PUT https://storage.example/loan-1002/credit-report.pdf?signature=...
PUT https://storage.example/loan-1002/signed-deed.pdf?signature=...
PUT https://storage.example/loan-1002/appraisal.pdf?signature=...
PUT https://storage.example/loan-1002/note.pdf?signature=...
PUT https://storage.example/loan-1002/closing-package.pdf?signature=...
PUT https://storage.example/loan-1002/w-9.pdf?signature=...
Submit checks that the named files arrived. The AI Validator then compares the uploaded loan tape with the guidelines' eligibility rules (skipping rules it cannot evaluate for lack of data).
POST /api/onboard/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
When every named file is present, the response has Submitted and one entry per loan:
{
"requestId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"name": "2026-10-01_rtl-batch",
"status": "Submitted",
"loans": [
{
"id": "loan-1001",
"figureId": "dddddddd-dddd-4ddd-dddd-dddddddddddd",
"errors": null,
"transformedAt": null,
"losStatus": null
},
{
"id": "loan-1002",
"figureId": "eeeeeeee-eeee-4eee-eeee-eeeeeeeeeeee",
"errors": null,
"transformedAt": null,
"losStatus": null
}
],
"errors": null
}
If a file is missing, status stays Created, errors lists request-level problems, and loans[].errors lists missing files for that loan.
Poll until status is Completed or Failed. While processing, the request moves through Submitted and Transformed. Each loan may show a losStatus of REQUESTED, IN_RETRY, SUCCESS, or FAILURE.
GET /api/onboard/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/status
When every loan finishes onboarding, a successful poll looks like this:
{
"requestId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"name": "2026-10-01_rtl-batch",
"status": "Completed",
"loans": [
{
"id": "loan-1001",
"figureId": "dddddddd-dddd-4ddd-dddd-dddddddddddd",
"errors": null,
"transformedAt": "2026-10-01T18:30:00Z",
"losStatus": "SUCCESS"
},
{
"id": "loan-1002",
"figureId": "eeeeeeee-eeee-4eee-eeee-eeeeeeeeeeee",
"errors": null,
"transformedAt": "2026-10-01T18:30:05Z",
"losStatus": "SUCCESS"
}
],
"errors": null
}
Sending Post-Close Updates
The recorded deed and recording information often arrive after onboarding. Send them as an update to the loan that is already onboarded.
There are two ways to send the same update. Choose one per update:
| Option | Endpoint | Tape fields you send | Use it when |
|---|---|---|---|
| A. Partial update | PATCH /api/onboard | Only the recording fields | You only have the new values. Every other tape field stays as it is. |
| B. Full row replacement | PUT /api/onboard | The complete tape row, including the recording fields | Your system re-exports the whole loan record. Fields left out are removed. |
Both options add the recorded deed the same way, and both use the same upload and submit steps.
Option A: Partial Update with PATCH
Send only the recording fields. Name the recorded deed on the loan. A file the loan does not already have is added. Figure stores it as loan-1001/recorded-deed.pdf, so both loans can use the same file name.
{
"name": "2026-10-15_rtl-recording",
"manifest": {
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"recordingDate": "2026-10-14",
"instrumentNumber": "2026-004821",
"recordingBook": "1520",
"recordingPage": "44",
"recordingCounty": "Travis"
},
{
"loanNumber": "loan-1002",
"recordingDate": "2026-10-14",
"instrumentNumber": "2026-004822",
"recordingBook": "1520",
"recordingPage": "45",
"recordingCounty": "Travis"
}
]
},
"loans": [
{
"id": "loan-1001",
"files": [
{ "fileName": "recorded-deed.pdf", "documentType": "RECORDED_DEED" }
]
},
{
"id": "loan-1002",
"files": [
{ "fileName": "recorded-deed.pdf", "documentType": "RECORDED_DEED" }
]
}
]
}
}
Option B: Full Row Replacement with PUT
Send the complete tape row for each loan, with the recording fields included. Sending only the recording fields with PUT drops the origination fields that are left out. The recorded deed is added the same way as in Option A.
{
"name": "2026-10-15_rtl-recording-replace",
"manifest": {
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"originalBalance": 250000,
"ficoScore": 720,
"dscrRatio": 1.25,
"recordingDate": "2026-10-14",
"instrumentNumber": "2026-004821",
"recordingBook": "1520",
"recordingPage": "44",
"recordingCounty": "Travis"
},
{
"loanNumber": "loan-1002",
"originalBalance": 180000,
"ficoScore": 690,
"dscrRatio": 1.40,
"recordingDate": "2026-10-14",
"instrumentNumber": "2026-004822",
"recordingBook": "1520",
"recordingPage": "45",
"recordingCounty": "Travis"
}
]
},
"loans": [
{
"id": "loan-1001",
"files": [
{ "fileName": "recorded-deed.pdf", "documentType": "RECORDED_DEED" }
]
},
{
"id": "loan-1002",
"files": [
{ "fileName": "recorded-deed.pdf", "documentType": "RECORDED_DEED" }
]
}
]
}
}
Upload and Submit (Both Options)
Because the update names new files, PATCH or PUT returns AwaitingUpload with signed URLs. Option A and Option B return the same shape (only the request name differs):
{
"updateRequestId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"name": "2026-10-15_rtl-recording",
"status": "AwaitingUpload",
"uploadUrls": {
"loan-1001/recorded-deed.pdf": "https://storage.example/loan-1001/recorded-deed.pdf?signature=...",
"loan-1002/recorded-deed.pdf": "https://storage.example/loan-1002/recorded-deed.pdf?signature=..."
},
"requests": [],
"loans": [],
"errors": null,
"nextAction": "Upload the requested files, then submit the update."
}
Upload each deed with PUT to its signed URL.
Submit starts processing after the staged files are present:
POST /api/onboard/updates/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
The submit response has Submitted, empty uploadUrls, and one child request per source onboard request the update touched. Each loan shows which child request it was placed into:
{
"updateRequestId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"name": "2026-10-15_rtl-recording",
"status": "Submitted",
"uploadUrls": {},
"requests": [
{
"requestId": "99999999-9999-9999-9999-999999999999",
"name": "2026-10-15_rtl-recording-child",
"sourceRequestId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
}
],
"loans": [
{
"id": "loan-1001",
"figureId": "dddddddd-dddd-4ddd-dddd-dddddddddddd",
"requestId": "99999999-9999-9999-9999-999999999999",
"overwrittenFiles": [],
"error": null
},
{
"id": "loan-1002",
"figureId": "eeeeeeee-eeee-4eee-eeee-eeeeeeeeeeee",
"requestId": "99999999-9999-9999-9999-999999999999",
"overwrittenFiles": [],
"error": null
}
],
"errors": null,
"nextAction": "Monitor child request progress by polling the update status."
}
If a document replaces an earlier file with the same name, overwrittenFiles lists that file name for the loan.
Poll until status is Completed or Rejected. While processing, the update may show Submitted or Transformed:
GET /api/onboard/updates/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
When every loan in the update finishes processing:
{
"updateRequestId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"name": "2026-10-15_rtl-recording",
"status": "Completed",
"uploadUrls": {},
"requests": [
{
"requestId": "99999999-9999-9999-9999-999999999999",
"name": "2026-10-15_rtl-recording-child",
"sourceRequestId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
}
],
"loans": [
{
"id": "loan-1001",
"figureId": "dddddddd-dddd-4ddd-dddd-dddddddddddd",
"requestId": "99999999-9999-9999-9999-999999999999",
"overwrittenFiles": [],
"error": null
},
{
"id": "loan-1002",
"figureId": "eeeeeeee-eeee-4eee-eeee-eeeeeeeeeeee",
"requestId": "99999999-9999-9999-9999-999999999999",
"overwrittenFiles": [],
"error": null
}
],
"errors": null,
"nextAction": "Monitor child request progress by polling the update status."
}
Correcting a Loan After Onboarding
Use this flow when a loan is already onboarded and you need to:
- correct incorrect origination data values, or
- add new requested fields that were not included on the original request
Keep the same loans[].id and externalIdKey as the original onboard request. Other tape fields can change; the loan identifier cannot. A different id or key onboards a new loan (NFT) rather than updating the one already on Provenance.
Choose one approach per correction:
| Option | Endpoint | What you send | Use it when |
|---|---|---|---|
| A. Partial update | PATCH /api/onboard | Only the tape fields you are correcting or adding | You only have the changed or new values. Every other tape field stays as it is. |
| B. Full row replacement | PUT /api/onboard | The complete tape row for each loan | Your system re-exports the whole loan record. Fields left out are removed. |
| C. Full replacement | POST /api/onboard with a new request name | A complete onboard manifest: full loan tape, the file containing the underwriting guidelines, loan metadata, and loan documents | You need to replace all origination data values and replace the loan documents for the loan(s). Same create, upload, and submit flow as the initial onboard request. |
Options A and B are merge updates to loans that are already onboarded. Option C is a new onboard request (unique name) that resubmits the full origination package for those loans.
For options A and B, documents are added or replaced when the file name already exists. Leaving a document out of files does not remove it. When the update names new files, upload them to the returned URLs, then POST /api/onboard/updates/{id}. See Sending Post-Close Updates above for upload, submit, and poll response examples.
When options A or B change only inline tape data and do not name any files, PATCH or PUT submits the update immediately and returns Submitted with empty uploadUrls.
Option A: Partial Update with PATCH
Send only the fields you are changing or adding. This example corrects ficoScore for both loans and leaves originalBalance and dscrRatio as they are:
{
"name": "2026-10-02_rtl-score-correction",
"manifest": {
"loanTape": {
"source": "PAYLOAD",
"data": [
{ "loanNumber": "loan-1001", "ficoScore": 735 },
{ "loanNumber": "loan-1002", "ficoScore": 705 }
]
},
"loans": [
{ "id": "loan-1001" },
{ "id": "loan-1002" }
]
}
}
Because no files are named, the response has Submitted and empty uploadUrls. Poll GET /api/onboard/updates/{updateRequestId} until status is Completed or Rejected.
Option B: Full Row Replacement with PUT
Send the complete tape row for each loan. Sending only the corrected fields with PUT drops origination fields that are left out:
{
"name": "2026-10-02_rtl-row-replacement",
"manifest": {
"loanTape": {
"source": "PAYLOAD",
"data": [
{
"loanNumber": "loan-1001",
"originalBalance": 250000,
"ficoScore": 735,
"dscrRatio": 1.25
},
{
"loanNumber": "loan-1002",
"originalBalance": 180000,
"ficoScore": 705,
"dscrRatio": 1.40
}
]
},
"loans": [
{ "id": "loan-1001" },
{ "id": "loan-1002" }
]
}
}
Option C: Full Replacement with POST
Send a new onboard request with a unique name and a complete manifest for the loan or batch—the same shape as the initial Create Onboard Request example. Include the full loan tape, the file containing the underwriting guidelines, Loan Participants, and every loan document you want on the loan after this correction.
This path replaces origination data values and loan documents for those loans rather than merging into the prior submission. Follow Create, Upload, Submit: POST /api/onboard, upload all named files, POST /api/onboard/{requestId}, then poll GET /api/onboard/{requestId}/status.
Use a new request name for each correction (for example 2026-10-02_rtl-full-replacement). Request names must be unique per API key.
Replacing a Loan Document (Options A and B)
Name the file on the loan in manifest.loans[].files. Upload a corrected file under the same file name to replace the stored document. That triggers AwaitingUpload and the upload-and-submit flow in Sending Post-Close Updates.
"loans": [
{
"id": "loan-1001",
"files": [
{ "fileName": "note.pdf", "documentType": "SIGNED_NOTE" }
]
}
]