# Term Sheets

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

Source: https://www.lev.com/docs/build/term-sheets

Last updated: June 2026

---
## 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.

| Endpoint | Description |
|----------|-------------|
| `GET /deals/{deal_id}/term-sheets` | List term sheets for a deal |
| `GET /deals/{deal_id}/term-sheets/{id}` | Get a single term sheet |
| `POST /deals/{deal_id}/term-sheets` | Create 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.

  `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

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deal_id` | `integer` | Yes | The deal ID |

#### Query Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `limit` | `integer` | No | Results per page (1–200, default 50) |
| `cursor` | `string` | No | Cursor for next page |

Response: `200`

#### Error Responses

- **401** (unauthorized): Authentication required
- **404** (not_found): Deal not found

## Get Term Sheet

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

Get a single term sheet

#### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deal_id` | `integer` | Yes | The deal ID |
| `term_sheet_id` | `integer` | Yes | The term sheet ID |

Response: `200`

#### Error Responses

- **401** (unauthorized): Authentication required
- **404** (not_found): Term sheet not found

## Create Term Sheet

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

Create a new term sheet against a placement

#### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deal_id` | `integer` | Yes | The deal ID |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `placement_id` | `integer` | Yes | ID of the placement (lender outreach) this quote belongs to. Must be a placement on this deal |
| `total_rate` | `number` | Yes | 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_funding` | `integer` | Yes | Provided loan amount (whole dollars) |
| `quote_type` | `string` | Yes | Quote type enum (see [Enums](#enums)) |
| `rate_type` | `string` | Yes | Rate type enum (`fixed` or `floating`) |
| `title` | `string` | No | Free-text title |
| `winning` | `boolean` | No | Mark as the winning quote on the deal. Defaults to `false` |
| `is_visible_to_borrower` | `boolean` | No | Whether the term sheet is visible to the borrower. Defaults to `true` |
| `base_rate` | `string` | No | 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_ltv` | `number` | No | Maximum loan-to-value as a decimal ratio (e.g. `0.70` for 70%) |
| `max_ltc` | `number` | No | Maximum loan-to-cost as a decimal ratio (e.g. `0.65` for 65%) |
| `additional_funding` | `integer` | No | Additional funding amount |
| `floor` | `number` | No | Rate floor as a percent (e.g. `5.00` for 5%) |
| `floor_type` | `string` | No | Floor type (`base_rate` or `total_rate`) |
| `term` | `integer` | No | Term length in months |
| `amortization` | `integer` | No | Amortization period in months |
| `io_period` | `integer` | No | Interest-only period in months |
| `extension_one` | `integer` | No | First extension period in months |
| `extension_two` | `integer` | No | Second extension period in months |
| `extension_three` | `integer` | No | Third extension period in months |
| `recourse` | `string` | No | Recourse category enum |
| `recourse_type` | `string` | No | Recourse type enum |
| `prepayment_penalty` | `string` | No | Prepayment penalty enum |
| `prepayment_penalty_details` | `string` | No | Free-text prepayment penalty details |
| `min_dscr` | `number` | No | Minimum debt-service coverage ratio (e.g. `1.25`) |
| `min_debt_yield` | `number` | No | Minimum debt yield as a decimal ratio (e.g. `0.08` for 8%) |
| `origination_fee` | `number` | No | Origination fee as a decimal ratio (e.g. `0.01` for 1%) |
| `extension_fee` | `number` | No | Extension fee as a decimal ratio (e.g. `0.0025` for 0.25%) |
| `exit_fee` | `number` | No | Exit fee as a decimal ratio (e.g. `0.005` for 0.5%) |
| `good_faith_deposit` | `number` | No | Good-faith deposit amount |
| `notes` | `string` | No | Free-text notes |
| `ir_details` | `string` | No | Free-text interest reserve details |
| `payment_method` | `string` | No | Payment method enum |
| `capital_source_type` | `string` | No | Capital source type enum (lender program classification) |

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

#### Error Responses

- **401** (unauthorized): Authentication required
- **404** (not_found): Placement not found; Deal not found
- **422** (validation_error): quote_type: input is not a valid enum member; base_rate: not a valid BaseRateNames member

- Supports idempotent writes with the `Idempotency-Key` header.

## Update Term Sheet

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

Update a term sheet (partial update)

#### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deal_id` | `integer` | Yes | The deal ID |
| `term_sheet_id` | `integer` | Yes | The term sheet ID |

#### Request Body

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `title` | `string` | No | Free-text title |
| `winning` | `boolean` | No | Mark or unmark as the winning quote on the deal |
| `total_rate` | `number` | No | 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_funding` | `integer` | No | Provided loan amount (whole dollars) |
| `quote_type` | `string` | No | Quote type enum (see [Enums](#enums)) |
| `rate_type` | `string` | No | Rate type enum (`fixed` or `floating`) |
| `base_rate` | `string|null` | No | 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_ltv` | `number` | No | Maximum loan-to-value as a decimal ratio (e.g. `0.70` for 70%) |
| `max_ltc` | `number` | No | Maximum loan-to-cost as a decimal ratio |
| `additional_funding` | `integer` | No | Additional funding amount |
| `floor` | `number` | No | Rate floor as a percent |
| `floor_type` | `string` | No | Floor type (`base_rate` or `total_rate`) |
| `term` | `integer` | No | Term length in months |
| `amortization` | `integer` | No | Amortization period in months |
| `io_period` | `integer` | No | Interest-only period in months |
| `extension_one` | `integer` | No | First extension period in months |
| `extension_two` | `integer` | No | Second extension period in months |
| `extension_three` | `integer` | No | Third extension period in months |
| `recourse` | `string` | No | Recourse category enum |
| `recourse_type` | `string` | No | Recourse type enum |
| `prepayment_penalty` | `string` | No | Prepayment penalty enum |
| `prepayment_penalty_details` | `string` | No | Free-text prepayment penalty details |
| `min_dscr` | `number` | No | Minimum debt-service coverage ratio (e.g. `1.25`) |
| `min_debt_yield` | `number` | No | Minimum debt yield as a decimal ratio |
| `origination_fee` | `number` | No | Origination fee as a decimal ratio (e.g. `0.01` for 1%) |
| `extension_fee` | `number` | No | Extension fee as a decimal ratio |
| `exit_fee` | `number` | No | Exit fee as a decimal ratio |
| `good_faith_deposit` | `number` | No | Good-faith deposit amount |
| `notes` | `string` | No | Free-text notes |
| `ir_details` | `string` | No | Free-text interest reserve details |
| `is_visible_to_borrower` | `boolean` | No | Whether the term sheet is visible to the borrower |
| `payment_method` | `string` | No | Payment method enum |
| `capital_source_type` | `string` | No | Capital source type enum |

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

#### Error Responses

- **400** (bad_request): Request body must contain at least one field to update
- **401** (unauthorized): Authentication required
- **404** (not_found): Term sheet not found
- **422** (validation_error): winning cannot be null. Send true or false to update it, or omit the field to leave it unchanged.; base_rate: not a valid BaseRateNames member

- Supports idempotent writes with the `Idempotency-Key` header.

## Delete Term Sheet

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

Soft-delete a term sheet

#### Path Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `deal_id` | `integer` | Yes | The deal ID |
| `term_sheet_id` | `integer` | Yes | The term sheet ID |

Response: `200`

#### Error Responses

- **401** (unauthorized): Authentication required
- **404** (not_found): Term sheet not found

## Term Sheet Object

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

### Summary Fields (List + Detail)

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Term sheet identifier |
| `deal_id` | integer\|null | Deal this term sheet belongs to |
| `title` | string\|null | Term sheet title |
| `lender_name` | string\|null | Display lender name. Masked non-owner reads use borrower-portal labels such as Lender A |
| `quote_type` | string\|null | Quote type (`guidance`, `indication`, `soft_quote`, `hard_quote`, `term_sheet`) |
| `initial_funding` | integer\|null | Initial funding amount |
| `total_rate` | number\|null | Conditional rate value. Spread over `base_rate` when a benchmark is set; all-in fixed rate when `base_rate` is null or `none-fixed`. |
| `base_rate` | string\|null | Display value of the base rate (e.g. `Treasury 5-Yr`, `SOFR 30-Day Avg`) or `none-fixed` |
| `base_rate_value` | number\|null | Base-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_spread` | number\|null | Effective spread as a percent for underwriting and comparison. For base-rate quotes, this normally equals `total_rate`. |
| `rate_type` | string\|null | Rate type (`fixed`, `floating`) |
| `term` | integer\|null | Loan term in months |
| `io_period` | integer\|null | Interest-only period in months |
| `recourse` | string\|null | Recourse type |
| `max_ltv` | number\|null | Maximum Loan-to-Value ratio |
| `max_ltc` | number\|null | Maximum Loan-to-Cost ratio |
| `origination_fee` | number\|null | Origination fee as a decimal ratio |
| `exit_fee` | number\|null | Exit fee as a decimal ratio |
| `org_id` | integer\|null | Lender organization ID. Null on masked non-owner reads |
| `placement_id` | integer\|null | Associated placement ID |
| `winning` | boolean\|null | Whether this is the winning term sheet |
| `is_visible_to_borrower` | boolean | Whether the term sheet is visible to the borrower |
| `notes` | string\|null | Free-form notes on the term sheet |
| `created_at` | string\|null | Creation timestamp |
| `updated_at` | string\|null | Last update timestamp |

### Additional Detail Fields (Detail Only)

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

| Field | Type | Description |
|-------|------|-------------|
| `capital_source_type` | string\|null | Capital source type |
| `recourse_type` | string\|null | Recourse type detail |
| `payment_method` | string\|null | Payment method |
| `prepayment_penalty` | string\|null | Prepayment penalty type |
| `prepayment_penalty_details` | string\|null | Prepayment penalty details |
| `amortization` | integer\|null | Amortization period in months |
| `extension_one` | integer\|null | First extension option (months) |
| `extension_two` | integer\|null | Second extension option (months) |
| `extension_three` | integer\|null | Third extension option (months) |
| `floor` | number\|null | Rate floor |
| `floor_type` | string\|null | Floor type |
| `good_faith_deposit` | number\|null | Good faith deposit amount |
| `min_dscr` | number\|null | Minimum DSCR requirement |
| `min_debt_yield` | number\|null | Minimum debt yield requirement |
| `ir_details` | string\|null | Interest reserve details |

## Enums

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

| Field | Valid values |
|-------|--------------|
| `quote_type` | `guidance`, `indication`, `soft_quote`, `hard_quote`, `term_sheet` |
| `rate_type` | `fixed`, `floating` |
| `recourse` | `personal_recourse`, `fund_corporate_recourse`, `non_recourse` |
| `recourse_type` | `full`, `partial`, `burn_off` |
| `floor_type` | `base_rate`, `total_rate` |
| `prepayment_penalty` | `step_down`, `defeasance`, `minimum_interest`, `yield_maintenance`, `minimum_multiple`, `swap_breakage`, `no_prepayment_penalty`, `no_ability_to_prepay`, `flat_fee`, `other` |
| `payment_method` | `accrued`, `partial`, `current_pay` |
| `capital_source_type` | `balance_sheet`, `agency`, `cmbs_clo`, `warehouse`, `sba` |
| `base_rate` | Either an enum key (e.g. `treasury_y5`, `sofr_m1`, `prime_rate`) or the matching display value returned by [`GET /market/base-rates`](/build/market-data#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 |