Optimind Systems Underwriting API¶
Welcome to the customer-facing documentation for the Optimind System's Underwriting API.
API Configuration¶
- Staging:
https://staging.api.optimindsystems.com - Production:
https://api.optimindsystems.com - Authentication: API key (passed via
x-api-key)- These API keys (Staging and Production) will be provided by Optimind Systems' engineering team when integration begins
Endpoints¶
This section outlines all available endpoints of the Underwriting API.
Score¶
POST /score: Submit product features and receive a score.
Required Parameters:¶
productId: Predetermined product ID for your underwriting modelfeatures: JSON blob of all required features for your underwriting model, must include a unique "assessment_id" for this approval
Renewal¶
If the renewal feature is enabled for this product:
Request:
- renewalId (string, optional): The opaque renewal id Optimind issued for this application in the renewal webhook. Include it to have this score recorded as a renewal; Optimind validates the id (scoped to your account) and records the result. Omit for a standard, non-renewal score.
Response (additional fields when renewalId is present):
- renewal_outcome (string): EXTEND_OFFER if at least one offer is recommended, NO_OFFER otherwise.
- Per offer in the score response:
- renewal_recommendation (string): RECOMMENDED if this offer passes all renewal criteria, NOT_RECOMMENDED otherwise.
Approval¶
-
POST /approval: Create or update an approval record on the decision of the scored application. -
GET /approval/product/{productId}/borrower/{borrowerId}/application/{applicationId}: Fetch a previously-saved approval record.
What It Does:¶
- Stores the approval decision and offer terms (if any) for a single borrower/application, allowing for Optimind business reporting and ongoing validation
- Supports updates: if the record already exists, you may send only the fields you want to change; omitted fields are preserved.
Required Parameters:¶
productIdborrowerIdapplicationIdapplicationTimemust be a valid date string.probabilityOfDefaultmust be a number between 0 and 1.modelVersionmust be a non-empty string.creditDecisionmust be a non-empty string.- If
creditDecision != NO_OFFER, these fields must be present:amount,currencyCode,term,termUnits,borrowerFeeType,borrowerFee,fundingStatus,paymentFrequency,paymentFrequencyUnit,expectedNumberOfPayments,paymentAmount,scheduledMaturityDate. - If present:
expectedNumberOfPaymentsmust be a positive integer.originationDatemust be a valid date string.currencyCodemust be a 3-letter code (e.g., USD).scheduledPayments[*].scheduleIdmust be a non-empty string.scheduledPayments[*].amountDuemust be a number > 0.scheduledPayments[*].scheduledDatemust be a valid date string.offersmust be an array of offer objects (see below).interestRatemust be a non-negative number (decimal percentage, e.g.0.15= 15%).renewalEligibleis optional. Omitted approvals are treated as eligible for renewal.- If
renewalEligibleisfalse,renewalIneligibleReasonis required. renewalIneligibleReasonmay only be sent whenrenewalEligibleisfalse.
Renewal Eligibility Updates¶
To exclude an approval from future renewal suggestions, update the approval with:
{
"productId": "cash_advance",
"borrowerId": "borrower-123",
"applicationId": "application-456",
"renewalEligible": false,
"renewalIneligibleReason": "Borrower is in an ineligible state"
}
Future renewal eligibility checks ignore approvals where renewalEligible is false.
Offers¶
The optional offers field records the list of product configurations that were shown to the borrower before they accepted one. Each offer object requires:
| Field | Type | Rules |
|---|---|---|
amount |
number | > 0 |
term |
integer | ≥ 1 |
termUnits |
string | non-empty (e.g. MONTHS, WEEKS) |
borrowerFeeType |
string | non-empty (e.g. ORIGINATION, FIXED) |
borrowerFee |
number | > 0 |
paymentFrequency |
integer | ≥ 1 |
paymentFrequencyUnit |
string | non-empty (e.g. MONTHS, WEEKS) |
paymentAmount |
number | > 0 |
interestRate |
number | optional; ≥ 0 (decimal percentage, e.g. 0.15 = 15%) |
Offers are stored independently in the approval_offer_data analytics table, keyed by (client_id, product_id, borrower_id, application_id, offer_id) where offer_id is the zero-based index of the offer in the array. On each update the existing rows for that application are replaced in full.
Responses:¶
200 OK: Successfully saved (create or update)- Body:
{ "ok": true }
- Body:
404 Not Found: Could not save approval becauseproductIddoesn't exist (for this API key / environment)- Body includes
errorCode: "APPROVAL_PRODUCT_NOT_FOUND" - Example:
{ "errorCode": "APPROVAL_PRODUCT_NOT_FOUND", "error": "Unknown productId for this environment: ..." }
- Body includes
GET Required Parameters:¶
- Path params:
productId,borrowerId,applicationId
GET Responses:¶
200 OK: Approval record404 Not Found: Approval record not found (orproductIdnot supported for this environment)
Payment¶
-
POST /payment: Create or update a payment record for an approval -
GET /payment/product/{productId}/borrower/{borrowerId}/application/{applicationId}: List all payment records for an application. -
GET /payment/product/{productId}/borrower/{borrowerId}/application/{applicationId}/payment/{paymentId}: Fetch a previously-saved payment record.
What It Does:¶
- Stores payment events for a borrower/application, allowing for Optimind business reporting and ongoing validation
- Supports updates: if the record already exists, you may send only the fields you want to change; omitted fields are preserved.
Required Parameters:¶
productIdborrowerIdapplicationIdpaymentIdpaymentDatemust be a valid date string.paymentAmountmust be a number > 0.paymentCurrencyCodemust be a 3-letter code (e.g., USD).scheduleIdmust be a non-empty string (max 128 chars).paymentMethodmust be a non-empty string (max 64 chars).paymentStatusmust be a non-empty string (max 64 chars).statusAfterPaymentmust be a non-empty string.- If present:
paymentDuemust be a number > 0.paymentDueDatemust be a valid date string.
Cross-entity checks (enforced server-side):¶
- The referenced approval must exist.
- The provided
scheduleIdmust exist on the approval'sscheduledPayments. - Payments are rejected if the approval has
creditDecision=NO_OFFER.
Responses:¶
200 OK: Successfully saved (create or update)- Body:
{ "ok": true }
- Body:
404 Not Found: Could not save payment because associated approval doesn't existerrorCode: "PAYMENT_APPROVAL_NOT_FOUND"
409 Conflict: Could not save payment because associated approval was not offerederrorCode: "PAYMENT_APPROVAL_NOT_OFFERED"
422 Unprocessable Entity: Could not save payment because associatedscheduleIdis not validerrorCode: "PAYMENT_INVALID_SCHEDULE_ID"
List GET Required Parameters:¶
- Path params:
productId,borrowerId,applicationId
List GET Responses:¶
200 OK:{ "payments": [...] }— array of payment records for the application404 Not Found: No payments found (orproductIdnot supported for this environment)
Single GET Required Parameters:¶
- Path params:
productId,borrowerId,applicationId,paymentId
Single GET Responses:¶
200 OK: Payment record404 Not Found: Payment record not found (orproductIdnot supported for this environment)
Getting Started¶
Contact support to obtain an API key and onboarding details.