Skip to content

Portal API

Borrower self-service portal backend API. These endpoints are used by the borrower-facing portal application and are scoped to the authenticated borrower's data.

Base permission: IsBorrowerUser (all endpoints except config)

Configuration

Get Portal Config

Public endpoint --- returns tenant branding for the login page.

GET /api/v1/portal/config

Permission: AllowAny

Response:

{
  "tenant_name": "Acme Lending",
  "logo_url": "https://cdn.acmelending.com/logo.png",
  "primary_color": "#1976d2",
  "secondary_color": "#dc004e",
  "support_email": "support@acmelending.com",
  "support_phone": "+18005551234"
}

Profile

Get Basic Profile

GET /api/v1/portal/me

Response:

{
  "id": "...",
  "email": "john.doe@email.com",
  "first_name": "John",
  "last_name": "Doe",
  "phone": "+12125551234"
}

Get Detailed Profile

GET /api/v1/portal/profile

Returns full borrower profile including addresses, communication preferences, and language preference.

Update Profile

PUT /api/v1/portal/profile
{
  "phone": "+12125559999",
  "language_preference": "es"
}

Update Communication Preferences

PUT /api/v1/portal/profile/communication-preferences
{
  "email_enabled": true,
  "sms_enabled": true,
  "letter_enabled": false,
  "marketing_enabled": false
}

Dashboard

Get Dashboard

Aggregated borrower dashboard with active loans, balances, and alerts.

GET /api/v1/portal/dashboard

Response:

{
  "borrower_name": "John Doe",
  "total_balance": "18570.23",
  "total_past_due": "0.00",
  "next_payment": {
    "amount": "312.50",
    "due_date": "2026-02-15",
    "loan_number": "LN-0001"
  },
  "loans": [
    {
      "id": "...",
      "loan_number": "LN-0001",
      "principal_balance": "8500.00",
      "status": "active",
      "next_payment_date": "2026-02-15",
      "next_payment_amount": "312.50"
    }
  ],
  "alerts": [
    {
      "type": "payment_due",
      "message": "Payment of $312.50 due in 5 days",
      "loan_id": "..."
    }
  ]
}

Loans

List Loans

GET /api/v1/portal/loans

Returns only loans associated with the authenticated borrower.

Get Loan Detail

GET /api/v1/portal/loans/{id}

Response:

{
  "id": "...",
  "loan_number": "LN-0001",
  "status": "active",
  "principal_amount": "10000.00",
  "principal_balance": "8500.00",
  "interest_rate": "0.085",
  "term_months": 36,
  "remaining_term": 30,
  "next_payment_date": "2026-02-15",
  "next_payment_amount": "312.50",
  "total_paid": "1500.00",
  "origination_date": "2025-07-15"
}

Get Amortization Schedule

GET /api/v1/portal/loans/{id}/amortization

Returns the full amortization schedule with period statuses.

Payments

List Payments

GET /api/v1/portal/loans/{id}/payments

Submit Payment

POST /api/v1/portal/loans/{id}/payments
{
  "amount": "312.50",
  "payment_instrument_id": "...",
  "payment_date": "2026-02-15"
}

Preview Payment

Dry-run showing how the payment would be allocated.

POST /api/v1/portal/loans/{id}/payments/preview
{
  "amount": "312.50"
}

Response:

{
  "amount": "312.50",
  "principal_applied": "250.00",
  "interest_applied": "62.50",
  "fees_applied": "0.00",
  "remaining_balance": "8250.00"
}

Autopay

Get Autopay Status

GET /api/v1/portal/loans/{id}/autopay

Enroll in Autopay

POST /api/v1/portal/loans/{id}/autopay/enroll
{
  "payment_instrument_id": "...",
  "amount_type": "minimum_due"
}

Cancel Autopay

POST /api/v1/portal/loans/{id}/autopay/cancel

Enable/Disable Autopay

POST /api/v1/portal/loans/{id}/autopay/enable

Payment Instruments

List Payment Instruments

GET /api/v1/portal/payment-instruments

Add Payment Instrument

POST /api/v1/portal/payment-instruments
{
  "instrument_type": "bank_account",
  "account_holder_name": "John Doe",
  "bank_name": "Chase",
  "routing_number": "021000021",
  "account_number_last_four": "6789",
  "account_type": "checking"
}

Delete Payment Instrument

DELETE /api/v1/portal/payment-instruments/{id}

Documents

List Documents

GET /api/v1/portal/documents

Returns documents associated with the borrower's loans (statements, disclosures, uploaded files).

Download Document

GET /api/v1/portal/documents/{id}/download

Returns a presigned download URL.

Upload Document

POST /api/v1/portal/documents/upload
{
  "loan_id": "...",
  "document_type": "income_verification",
  "filename": "paystub_jan_2026.pdf",
  "content_type": "application/pdf"
}

Returns a presigned upload URL (same three-step flow as admin).

Confirm Upload

POST /api/v1/portal/documents/{id}/confirm-upload

Support Cases

List Cases

GET /api/v1/portal/support/cases

Create Case

POST /api/v1/portal/support/cases
{
  "loan_id": "...",
  "subject": "Payment not reflected on statement",
  "description": "I made a payment on Jan 10 but it's not showing on my account.",
  "case_type": "dispute"
}

Get Case Detail

GET /api/v1/portal/support/cases/{id}

Includes message thread history.

Add Message to Case

POST /api/v1/portal/support/cases/{id}/messages
{
  "message": "I've attached my bank statement showing the payment."
}

Hardship Applications

List Applications

GET /api/v1/portal/hardship

Get Application

GET /api/v1/portal/hardship/{id}

Submit Application

POST /api/v1/portal/hardship
{
  "loan_id": "...",
  "hardship_type": "job_loss",
  "description": "Lost employment in December 2025",
  "monthly_income": "2000.00",
  "monthly_expenses": "1800.00",
  "requested_action": "forbearance"
}

The hardship application triggers a case for review by the servicing team.

Portal Contacts

Borrowers can manage their own contact information:

Method Path Description
GET /addresses List addresses
POST /addresses Add address
GET /emails List emails
POST /emails Add email
GET /phones List phones
POST /phones Add phone

See Also