Build

Term Sheets

Create, update, delete, and view term sheet data for deals in the Lev API.

Updated June 2026
GET/api/external/v2/deals/{deal_id}/term-sheets
GET/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}
POST/api/external/v2/deals/{deal_id}/term-sheets
PATCH/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}
DELETE/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}

Overview

Term sheets are loan quotes attached to a placement on a deal. A deal can have many term sheets (one per quote received), and one can be marked as the winning quote.

EndpointDescription
GET /deals/{deal_id}/term-sheetsList term sheets for a deal
GET /deals/{deal_id}/term-sheets/{id}Get a single term sheet
POST /deals/{deal_id}/term-sheetsCreate a new term sheet against a placement
PATCH /deals/{deal_id}/term-sheets/{id}Update a term sheet (partial update)
DELETE /deals/{deal_id}/term-sheets/{id}Soft-delete a term sheet (reversible by Lev support)

placement_id and deal_id are set at create time and cannot be reassigned. To move a term sheet to a different placement, delete it and create a new one.

Rate field semantics

total_rate is conditional. If the term sheet has a benchmark base_rate, total_rate is the spread over that base rate. If the term sheet has no benchmark (base_rate is null or none-fixed), total_rate is the all-in fixed rate. For base-rate quotes, calculate the displayed all-in rate as base_rate_value + total_rate when both values are known. effective_spread is the spread used for underwriting and comparison; for product-created base-rate quotes, it normally equals total_rate.

Term sheet responses include lender_name for display. When a term sheet belongs to a masked placement and you are not viewing from the deal owner's account, lender_name uses the same generic borrower-portal label style as Lender A and org_id is null.

List Term Sheets

GET/api/external/v2/deals/{deal_id}/term-sheets

List term sheets for a deal

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
limitinteger
Results per page (1–200, default 50)
cursorstring
Cursor for next page

Response (200):

{
  "request_id": "e7f8a9b0-c1d2-3456-0123-567890123456",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": [
    {
      "id": 15,
      "title": "JPMorgan Chase — Stabilized Multifamily",
      "lender_name": "JPMorgan Chase",
      "quote_type": "soft_quote",
      "rate_type": "fixed",
      "total_rate": 1.50,
      "base_rate": "Treasury 5-Yr",
      "base_rate_value": 4.35,
      "effective_spread": 1.50,
      "initial_funding": 5000000,
      "io_period": 24,
      "max_ltv": 0.70,
      "max_ltc": null,
      "origination_fee": 0.01,
      "term": 120,
      "recourse": "non_recourse",
      "org_id": 3200,
      "placement_id": 310,
      "winning": false,
      "notes": "Rate locks at application; 60-day close.",
      "created_at": "2026-02-10T14:00:00Z",
      "updated_at": "2026-03-01T09:15:00Z"
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 50,
    "has_more": false,
    "next_cursor": null
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Deal not foundThe deal_id doesn't exist or isn't accessible to the authenticated user

Get Term Sheet

GET/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}

Get a single term sheet

Path parameters
deal_idintegerrequired
The deal ID
term_sheet_idintegerrequired
The term sheet ID

Response (200):

{
  "request_id": "f8a9b0c1-d2e3-4567-1234-678901234567",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": {
    "id": 15,
    "title": "JPMorgan Chase — Stabilized Multifamily",
    "lender_name": "JPMorgan Chase",
    "quote_type": "soft_quote",
    "rate_type": "fixed",
    "total_rate": 1.50,
    "base_rate": "Treasury 5-Yr",
    "initial_funding": 5000000,
    "io_period": 24,
    "max_ltv": 0.70,
    "max_ltc": null,
    "origination_fee": 0.01,
    "term": 120,
    "recourse": "non_recourse",
    "org_id": 3200,
    "placement_id": 310,
    "winning": false,
    "created_at": "2026-02-10T14:00:00Z",
    "updated_at": "2026-03-01T09:15:00Z",
    "capital_source_type": "balance_sheet",
    "base_rate_value": 4.35,
    "effective_spread": 1.50,
    "recourse_type": "full",
    "payment_method": "current_pay",
    "prepayment_penalty": "yield_maintenance",
    "prepayment_penalty_details": "Yield maintenance for first 7 years, 1% thereafter",
    "amortization": 360,
    "extension_one": 12,
    "extension_two": null,
    "extension_three": null,
    "floor": 5.00,
    "floor_type": "total_rate",
    "good_faith_deposit": 50000.0,
    "min_dscr": 1.25,
    "min_debt_yield": 0.08,
    "ir_details": null,
    "notes": "Subject to property inspection and environmental review"
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Term sheet not foundThe term_sheet_id or deal_id doesn't exist or isn't accessible to the authenticated user

Create Term Sheet

POST/api/external/v2/deals/{deal_id}/term-sheets

Create a new term sheet against a placement

Supports the Idempotency-Key header to prevent duplicate creation. Requires the termsheets:write scope.

Path parameters
deal_idintegerrequired
The deal ID
Request body (required)
placement_idintegerrequired
ID of the placement (lender outreach) this quote belongs to. Must be a placement on this deal
total_ratenumberrequired
Rate as a percent. Send the spread when `base_rate` is set, and send the all-in fixed rate when `base_rate` is omitted or `none-fixed`
initial_fundingintegerrequired
Provided loan amount (whole dollars)
quote_typestringrequired
Quote type enum (see [Enums](#enums))
rate_typestringrequired
Rate type enum (`fixed` or `floating`)
Request body (optional)
titlestring
Free-text title
winningboolean
Mark as the winning quote on the deal. Defaults to `false`
is_visible_to_borrowerboolean
Whether the term sheet is visible to the borrower. Defaults to `true`
base_ratestring
Base-rate identifier — accepts either an enum key (e.g. `treasury_y5`, `sofr_m1`, `prime_rate`) or the display value returned by [`GET /market/base-rates`](/build/market-data#base-rates) (e.g. `Treasury 5-Yr`, `SOFR 30-Day Avg`, `Prime Rate`). Use `none-fixed` for fixed-rate quotes with no underlying benchmark. When this is a real base-rate identifier, send `total_rate` as the spread over that base rate
max_ltvnumber
Maximum loan-to-value as a decimal ratio (e.g. `0.70` for 70%)
max_ltcnumber
Maximum loan-to-cost as a decimal ratio (e.g. `0.65` for 65%)
additional_fundinginteger
Additional funding amount
floornumber
Rate floor as a percent (e.g. `5.00` for 5%)
floor_typestring
Floor type (`base_rate` or `total_rate`)
terminteger
Term length in months
amortizationinteger
Amortization period in months
io_periodinteger
Interest-only period in months
extension_oneinteger
First extension period in months
extension_twointeger
Second extension period in months
extension_threeinteger
Third extension period in months
recoursestring
Recourse category enum
recourse_typestring
Recourse type enum
prepayment_penaltystring
Prepayment penalty enum
prepayment_penalty_detailsstring
Free-text prepayment penalty details
min_dscrnumber
Minimum debt-service coverage ratio (e.g. `1.25`)
min_debt_yieldnumber
Minimum debt yield as a decimal ratio (e.g. `0.08` for 8%)
origination_feenumber
Origination fee as a decimal ratio (e.g. `0.01` for 1%)
extension_feenumber
Extension fee as a decimal ratio (e.g. `0.0025` for 0.25%)
exit_feenumber
Exit fee as a decimal ratio (e.g. `0.005` for 0.5%)
good_faith_depositnumber
Good-faith deposit amount
notesstring
Free-text notes
ir_detailsstring
Free-text interest reserve details
payment_methodstring
Payment method enum
capital_source_typestring
Capital source type enum (lender program classification)

See Enums for the full list of valid values for each enum field.

Quote visibility after create

The list and detail endpoints filter out term sheets whose quote_type is not in the default-visible set or whose is_visible_to_borrower is false. A successful create followed by a GET returning 404 means the row exists but is hidden by policy — re-check the quote_type and is_visible_to_borrower values you sent.

curl -X POST "https://api.lev.com/api/external/v2/deals/101/term-sheets" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "placement_id": 310,
    "total_rate": 1.50,
    "initial_funding": 5000000,
    "quote_type": "soft_quote",
    "rate_type": "fixed",
    "base_rate": "treasury_y5",
    "term": 120,
    "io_period": 24,
    "max_ltv": 0.70,
    "recourse": "non_recourse",
    "origination_fee": 0.01,
    "title": "JPMorgan Chase — Stabilized Multifamily"
  }'

Response (201): returns the full term-sheet detail object (see Term Sheet Object).

401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Placement not found`placement_id` doesn't exist, isn't on this `deal_id`, or isn't accessible to the authenticated user
404not_found
Deal not found`deal_id` doesn't exist or isn't accessible to the authenticated user
422validation_error
quote_type: input is not a valid enum memberUnknown enum value sent for one of the enum fields
422validation_error
base_rate: not a valid BaseRateNames memberUnknown `base_rate` value — the response includes the full list of valid options

Update Term Sheet

PATCH/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}

Update a term sheet (partial update)

Supports the Idempotency-Key header. Requires the termsheets:write scope. Send only the fields you want to change — at least one body field is required.

Path parameters
deal_idintegerrequired
The deal ID
term_sheet_idintegerrequired
The term sheet ID

placement_id and deal_id are locked at create time and cannot be reassigned — to move a term sheet to a different placement, delete it and create a new one.

Request body
titlestring
Free-text title
winningboolean
Mark or unmark as the winning quote on the deal
total_ratenumber
Rate as a percent. Interpreted against the resulting `base_rate`: spread when `base_rate` is set, all-in fixed rate when `base_rate` is `null` or `none-fixed`. Omitting `base_rate` leaves the existing base-rate setting unchanged
initial_fundinginteger
Provided loan amount (whole dollars)
quote_typestring
Quote type enum (see [Enums](#enums))
rate_typestring
Rate type enum (`fixed` or `floating`)
base_ratestring|null
Base-rate identifier — enum key (e.g. `treasury_y5`) or display value (e.g. `Treasury 5-Yr`). Omit to leave unchanged. Send `null` or `none-fixed` for fixed-rate quotes with no benchmark; see special handling below
max_ltvnumber
Maximum loan-to-value as a decimal ratio (e.g. `0.70` for 70%)
max_ltcnumber
Maximum loan-to-cost as a decimal ratio
additional_fundinginteger
Additional funding amount
floornumber
Rate floor as a percent
floor_typestring
Floor type (`base_rate` or `total_rate`)
terminteger
Term length in months
amortizationinteger
Amortization period in months
io_periodinteger
Interest-only period in months
extension_oneinteger
First extension period in months
extension_twointeger
Second extension period in months
extension_threeinteger
Third extension period in months
recoursestring
Recourse category enum
recourse_typestring
Recourse type enum
prepayment_penaltystring
Prepayment penalty enum
prepayment_penalty_detailsstring
Free-text prepayment penalty details
min_dscrnumber
Minimum debt-service coverage ratio (e.g. `1.25`)
min_debt_yieldnumber
Minimum debt yield as a decimal ratio
origination_feenumber
Origination fee as a decimal ratio (e.g. `0.01` for 1%)
extension_feenumber
Extension fee as a decimal ratio
exit_feenumber
Exit fee as a decimal ratio
good_faith_depositnumber
Good-faith deposit amount
notesstring
Free-text notes
ir_detailsstring
Free-text interest reserve details
is_visible_to_borrowerboolean
Whether the term sheet is visible to the borrower
payment_methodstring
Payment method enum
capital_source_typestring
Capital source type enum

See Enums for the full list of valid values for each enum field.

Special handling for boolean fields. Sending winning: null or is_visible_to_borrower: null returns 422 — these fields require an explicit boolean. Omit the field to leave it unchanged, or send true/false.

Special handling for base_rate. Most fixed-rate quotes still reference a benchmark (e.g. treasury_y5 for "Treasury 5-Yr + spread") — pair rate_type: "fixed" with the benchmark name. Omitting base_rate leaves the existing setting unchanged. Use base_rate: null or "none-fixed" only when the lender quoted a flat rate with no underlying index reference. When the resulting term sheet has a benchmark base_rate, total_rate is the spread; when the resulting base_rate is null or none-fixed, total_rate is the all-in fixed rate.

curl -X PATCH "https://api.lev.com/api/external/v2/deals/101/term-sheets/15" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "base_rate": "treasury_y5",
    "total_rate": 1.60,
    "winning": true,
    "notes": "Lender widened spread by 10bps after market move; deal team flagged as winning"
  }'

Response (200): returns the updated term-sheet detail object.

400bad_request
Request body must contain at least one field to updateEmpty request body
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Term sheet not found`term_sheet_id` or `deal_id` doesn't exist, doesn't match, or isn't accessible
422validation_error
winning cannot be null. Send true or false to update it, or omit the field to leave it unchanged.Explicit `null` on `winning` or `is_visible_to_borrower`
422validation_error
base_rate: not a valid BaseRateNames memberUnknown `base_rate` value

Delete Term Sheet

DELETE/api/external/v2/deals/{deal_id}/term-sheets/{term_sheet_id}

Soft-delete a term sheet

Soft delete — the term sheet is marked deleted and excluded from subsequent reads, but can be restored by Lev support. Requires the termsheets:write scope.

Path parameters
deal_idintegerrequired
The deal ID
term_sheet_idintegerrequired
The term sheet ID
curl -X DELETE "https://api.lev.com/api/external/v2/deals/101/term-sheets/15" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "timestamp": "2026-05-19T15:30:45Z",
  "data": {
    "deleted": true
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Term sheet not found`term_sheet_id` or `deal_id` doesn't exist, doesn't match, or isn't accessible

Term Sheet Object

The list endpoint returns a summary response, while the detail endpoint returns additional fields.

Summary Fields (List + Detail)

FieldTypeDescription
idintegerTerm sheet identifier
deal_idinteger|nullDeal this term sheet belongs to
titlestring|nullTerm sheet title
lender_namestring|nullDisplay lender name. Masked non-owner reads use borrower-portal labels such as Lender A
quote_typestring|nullQuote type (guidance, indication, soft_quote, hard_quote, term_sheet)
initial_fundinginteger|nullInitial funding amount
total_ratenumber|nullConditional rate value. Spread over base_rate when a benchmark is set; all-in fixed rate when base_rate is null or none-fixed.
base_ratestring|nullDisplay value of the base rate (e.g. Treasury 5-Yr, SOFR 30-Day Avg) or none-fixed
base_rate_valuenumber|nullBase-rate snapshot as a percent. For base-rate quotes, display all-in rate as base_rate_value + total_rate when both values are known
effective_spreadnumber|nullEffective spread as a percent for underwriting and comparison. For base-rate quotes, this normally equals total_rate.
rate_typestring|nullRate type (fixed, floating)
terminteger|nullLoan term in months
io_periodinteger|nullInterest-only period in months
recoursestring|nullRecourse type
max_ltvnumber|nullMaximum Loan-to-Value ratio
max_ltcnumber|nullMaximum Loan-to-Cost ratio
origination_feenumber|nullOrigination fee as a decimal ratio
exit_feenumber|nullExit fee as a decimal ratio
org_idinteger|nullLender organization ID. Null on masked non-owner reads
placement_idinteger|nullAssociated placement ID
winningboolean|nullWhether this is the winning term sheet
is_visible_to_borrowerbooleanWhether the term sheet is visible to the borrower
notesstring|nullFree-form notes on the term sheet
created_atstring|nullCreation timestamp
updated_atstring|nullLast update timestamp

Additional Detail Fields (Detail Only)

These fields are only returned by the GET /deals/{deal_id}/term-sheets/{id} endpoint:

FieldTypeDescription
capital_source_typestring|nullCapital source type
recourse_typestring|nullRecourse type detail
payment_methodstring|nullPayment method
prepayment_penaltystring|nullPrepayment penalty type
prepayment_penalty_detailsstring|nullPrepayment penalty details
amortizationinteger|nullAmortization period in months
extension_oneinteger|nullFirst extension option (months)
extension_twointeger|nullSecond extension option (months)
extension_threeinteger|nullThird extension option (months)
floornumber|nullRate floor
floor_typestring|nullFloor type
good_faith_depositnumber|nullGood faith deposit amount
min_dscrnumber|nullMinimum DSCR requirement
min_debt_yieldnumber|nullMinimum debt yield requirement
ir_detailsstring|nullInterest reserve details

Enums

All enum values are lowercase on the wire. Unknown values return 422 with the full list of valid options.

FieldValid values
quote_typeguidance, indication, soft_quote, hard_quote, term_sheet
rate_typefixed, floating
recoursepersonal_recourse, fund_corporate_recourse, non_recourse
recourse_typefull, partial, burn_off
floor_typebase_rate, total_rate
prepayment_penaltystep_down, defeasance, minimum_interest, yield_maintenance, minimum_multiple, swap_breakage, no_prepayment_penalty, no_ability_to_prepay, flat_fee, other
payment_methodaccrued, partial, current_pay
capital_source_typebalance_sheet, agency, cmbs_clo, warehouse, sba
base_rateEither an enum key (e.g. treasury_y5, sofr_m1, prime_rate) or the matching display value returned by GET /market/base-rates (e.g. Treasury 5-Yr, SOFR 30-Day Avg, Prime Rate). Both forms are accepted on write. Use the literal none-fixed for fixed-rate quotes with no underlying benchmark. When you send a real base-rate value, send total_rate as the spread over that base rate
More in this section