Skip to content

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 model
  • features: 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:

  • productId
  • borrowerId
  • applicationId
  • applicationTime must be a valid date string.
  • probabilityOfDefault must be a number between 0 and 1.
  • modelVersion must be a non-empty string.
  • creditDecision must 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:
    • expectedNumberOfPayments must be a positive integer.
    • originationDate must be a valid date string.
    • currencyCode must be a 3-letter code (e.g., USD).
    • scheduledPayments[*].scheduleId must be a non-empty string.
    • scheduledPayments[*].amountDue must be a number > 0.
    • scheduledPayments[*].scheduledDate must be a valid date string.
    • offers must be an array of offer objects (see below).
    • interestRate must be a non-negative number (decimal percentage, e.g. 0.15 = 15%).
    • renewalEligible is optional. Omitted approvals are treated as eligible for renewal.
    • If renewalEligible is false, renewalIneligibleReason is required.
    • renewalIneligibleReason may only be sent when renewalEligible is false.

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 }
  • 404 Not Found: Could not save approval because productId doesn'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: ..." }

GET Required Parameters:

  • Path params: productId, borrowerId, applicationId

GET Responses:

  • 200 OK: Approval record
  • 404 Not Found: Approval record not found (or productId not 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:

  • productId
  • borrowerId
  • applicationId
  • paymentId
  • paymentDate must be a valid date string.
  • paymentAmount must be a number > 0.
  • paymentCurrencyCode must be a 3-letter code (e.g., USD).
  • scheduleId must be a non-empty string (max 128 chars).
  • paymentMethod must be a non-empty string (max 64 chars).
  • paymentStatus must be a non-empty string (max 64 chars).
  • statusAfterPayment must be a non-empty string.
  • If present:
    • paymentDue must be a number > 0.
    • paymentDueDate must be a valid date string.

Cross-entity checks (enforced server-side):

  • The referenced approval must exist.
  • The provided scheduleId must exist on the approval's scheduledPayments.
  • Payments are rejected if the approval has creditDecision=NO_OFFER.

Responses:

  • 200 OK: Successfully saved (create or update)
    • Body: { "ok": true }
  • 404 Not Found: Could not save payment because associated approval doesn't exist
    • errorCode: "PAYMENT_APPROVAL_NOT_FOUND"
  • 409 Conflict: Could not save payment because associated approval was not offered
    • errorCode: "PAYMENT_APPROVAL_NOT_OFFERED"
  • 422 Unprocessable Entity: Could not save payment because associated scheduleId is not valid
    • errorCode: "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 application
  • 404 Not Found: No payments found (or productId not supported for this environment)

Single GET Required Parameters:

  • Path params: productId, borrowerId, applicationId, paymentId

Single GET Responses:

  • 200 OK: Payment record
  • 404 Not Found: Payment record not found (or productId not supported for this environment)

Getting Started

Contact support to obtain an API key and onboarding details.