Build

Deals

Full CRUD operations, indexed deal-data search, generated memos, document and vault access, and Deal Room checklist reads for deals in the Lev API.

Updated July 2026
GET/api/external/v2/deals
GET/api/external/v2/deals/{deal_id}Structured deal detail
POST/api/external/v2/deals/{deal_id}/index/searchCanonical indexed facts
POST/api/external/v2/deals/{deal_id}/index/observationsSource values behind a fact
PATCH/api/external/v2/deals/{deal_id}/index/factsChange a deal fact's canonical value
GET/api/external/v2/deals/{deal_id}/index/metric-definitionsRecordable metric catalog
GET/api/external/v2/deals/{deal_id}/index/entitiesEntities you can attach facts to
POST/api/external/v2/deals/{deal_id}/index/factsRecord user-supplied metric values
GET/api/external/v2/deals/{deal_id}/vaultsA deal's vaults — Resources and Deal Rooms
GET/api/external/v2/deals/{deal_id}/documentsUploaded files across a deal's vaults
GET/api/external/v2/deals/{deal_id}/documents/{document_id}Metadata for one uploaded file
GET/api/external/v2/deals/{deal_id}/documents/{document_id}/downloadShort-lived signed file link
GET/api/external/v2/deals/{deal_id}/checklistsDeal Room checklists with task status and attached file references
GET/api/external/v2/deals/{deal_id}/memosA deal's memos (published + draft)
GET/api/external/v2/deals/{deal_id}/memos/{memo_uuid}One memo with signed PDF links
GET/api/external/v2/deals/{deal_id}/notesNotes logged on a deal
POST/api/external/v2/deals/{deal_id}/notes
PATCH/api/external/v2/deals/{deal_id}/notes/{note_id}
DELETE/api/external/v2/deals/{deal_id}/notes/{note_id}
GET/api/external/v2/checklist-tasks/{task_id}/notesComments on a checklist task
POST/api/external/v2/checklist-tasks/{task_id}/notes
PATCH/api/external/v2/checklist-tasks/{task_id}/notes/{note_id}
DELETE/api/external/v2/checklist-tasks/{task_id}/notes/{note_id}
POST/api/external/v2/checklist-tasks
PATCH/api/external/v2/checklist-tasks/{task_id}
POST/api/external/v2/checklist-tasks/{task_id}/complete

Overview

The deals endpoints support full CRUD operations with filtering, sorting, pagination, sparse fieldsets, and optional sub-resource includes.

EndpointDescription
GET /dealsList deals with filtering and pagination
GET /deals/{id}Get a single deal
POST /deals/{id}/index/searchSearch canonical indexed facts and source provenance for a deal
POST /deals/{id}/index/observationsList candidate observations (per-document extractions) behind a fact
PATCH /deals/{id}/index/factsUpdate a single canonical fact value (direct replacement or promote an observation)
GET /deals/{id}/index/metric-definitionsList the metrics that can be recorded on a deal
GET /deals/{id}/index/entitiesList the entities (deal, properties, sponsor) you can attach facts to
POST /deals/{id}/index/factsRecord one or more user-supplied metric values
GET /deals/{id}/vaultsList a deal's vaults — its Resources area and any shared Deal Rooms
GET /deals/{id}/documentsList uploaded documents across all of a deal's vaults
GET /deals/{id}/documents/{document_id}Fetch one uploaded document's metadata
GET /deals/{id}/documents/{document_id}/downloadFetch a short-lived signed download link for one uploaded document
GET /deals/{id}/checklistsList each Deal Room's checklist — sections, tasks, document types, and task-linked files
GET /deals/{id}/memosList a deal's memos (deal books) — published and draft
GET /deals/{id}/memos/{memo_uuid}Fetch one memo with signed PDF download links
GET /deals/{id}/notesList notes logged on a deal
POST /deals/{id}/notesAdd a note to a deal
PATCH /deals/{id}/notes/{note_id}Edit a deal note
DELETE /deals/{id}/notes/{note_id}Delete a deal note
GET /checklist-tasks/{id}/notesList comments on a checklist task (borrower-portal comments)
POST /checklist-tasks/{id}/notesAdd a comment to a checklist task
PATCH /checklist-tasks/{id}/notes/{note_id}Edit a checklist task comment
DELETE /checklist-tasks/{id}/notes/{note_id}Delete a checklist task comment
POST /checklist-tasksCreate a checklist task — a document request or to-do on a deal
PATCH /checklist-tasks/{id}Update a checklist task — retitle, re-status, reassign, set a due date, or reopen
POST /checklist-tasks/{id}/completeMark a checklist task complete (also approves its attached files)
POST /dealsCreate a new deal, optionally with deal-level financials
PATCH /deals/{id}Update deal fields and writable deal-level financials
DELETE /deals/{id}Archive (soft-delete) a deal

List Deals

GET/api/external/v2/deals

List deals with pagination, filtering, and sorting

Query parameters
limitinteger
Results per page (1–200, default 50)
cursorstring
Cursor for next page (mutually exclusive with sort)
offsetinteger
Offset for pagination (requires sort)
sortstring
Sort fields: title, loan_amount, created_at, updated_at. Prefix with - for descending
fieldsstring
Comma-separated fields to include (id always included)
includestring
Sub-resources to embed: financials, properties, team, pipelines
filter[loan_type]LoanType
Filter by loan type enum name, such as heavy_bridge or permanent
filter[transaction_type]TransactionType
Filter by transaction type enum name, such as acquisition or refinance
filter[business_plan]BusinessPlanType
Filter by business plan enum name
filter[archived]boolean
Filter by archived state. Omit to return both active and archived deals; pass true for only archived, false for only active
filter[loan_amount][gte]number
Minimum loan amount
filter[loan_amount][lte]number
Maximum loan amount
filter[created_at][gte]string
Created after (ISO 8601)
filter[created_at][lte]string
Created before (ISO 8601)
Archived state is independent of pipeline status

Archiving a deal sets its archived and archived_at fields. It does not rewrite the deal's pipeline status, so an archived deal can still report a live-looking stage such as Reaching Out To Lenders. To separate active deals from archived ones, read the archived field or filter with filter[archived]. Do not infer archived state from a stalled pipeline stage.

curl -X GET "https://api.lev.com/api/external/v2/deals?limit=10&include=financials&sort=-created_at" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "...",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": [
    {
      "id": 101,
      "title": "123 Main St Acquisition",
      "loan_amount": 5000000.0,
      "loan_type": "heavy_bridge",
      "transaction_type": "acquisition",
      "business_plan": "value_add",
      "description": "Mixed-use acquisition in downtown",
      "estimated_close_date": "2026-06-01",
      "close_date": null,
      "owner_account_id": 56,
      "created_at": "2026-01-15T10:00:00Z",
      "updated_at": "2026-03-10T14:30:00Z",
      "archived": false,
      "archived_at": null,
      "financials": {
        "id": 201,
        "noi": 450000.0,
        "purchase_price": 6500000.0,
        "appraised_value": 7000000.0,
        "ltv": 0.714,
        "dscr": 1.25
      }
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 10,
    "offset": 0,
    "has_more": true
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
400bad_request
cursor and sort cannot be combined; use offset pagination when sortingBoth cursor and sort query parameters are provided

Get Deal

GET/api/external/v2/deals/{deal_id}

Get a single deal by ID

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
includestring
Sub-resources to embed: financials, properties, team, pipelines
fieldsstring
Comma-separated fields to include

Response (200):

{
  "request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": {
    "id": 101,
    "title": "123 Main St Acquisition",
    "loan_amount": 5000000.0,
    "loan_type": "heavy_bridge",
    "transaction_type": "acquisition",
    "business_plan": "value_add",
    "description": "Mixed-use acquisition in downtown Chicago",
    "estimated_close_date": "2026-06-01",
    "close_date": null,
    "owner_account_id": 56,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-03-10T14:30:00Z",
    "archived": false,
    "archived_at": 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

Search Index

POST/api/external/v2/deals/{deal_id}/index/search

Search canonical indexed deal facts by natural-language context

Use Index search when you need source-backed facts that may live in deal attachments or normalized underwriting data. It complements GET /deals/{deal_id}: use GET /deals/{deal_id} for structured deal fields, then use Index search for targeted questions about metrics, loan terms, proceeds, rent roll, occupancy, sponsor background, valuations, capex, dates, and source documents.

The endpoint searches Metric SOT / Index data for one deal. It does not return an exhaustive full Index export.

Path parameters
deal_idintegerrequired
The deal ID
Request body
contextstringrequired
Natural-language search context (1-4000 characters). Be specific about the metric or topic you want.
min_scorenumber
Minimum similarity threshold from 0 to 1. Defaults to 0.3.
limitinteger
Maximum ranked facts to return. Defaults to 20 and is clamped to 1-200.
include_signed_urlsboolean
When true, document-backed source records may include short-lived signed URLs for inspection or download.
curl -X POST "https://api.lev.com/api/external/v2/deals/101/index/search" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "context": "in-place NOI and source documents",
    "min_score": 0.3,
    "limit": 5,
    "include_signed_urls": false
  }'

Response (200):

{
  "request_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "timestamp": "2026-05-06T15:30:45Z",
  "data": [
    {
      "id": "1",
      "sot_id": 1,
      "metric_key": "deal_financials.in_place_noi",
      "metric_id": 42,
      "metric_label": "In-place NOI",
      "value_text": "$1,250,000",
      "value_type": "currency",
      "context": "The appraisal reports trailing twelve month NOI.",
      "summary": "In-place NOI is $1.25M based on the appraisal.",
      "period_type": "point_in_time",
      "period_value": null,
      "entity_type": "deal",
      "entity_id": null,
      "entity_ref": "deal:123",
      "group_ref": null,
      "category_id": 5,
      "category_label": "Deal Financials",
      "needs_review": false,
      "score": 0.87,
      "source": {
        "type": "document",
        "document_id": 99,
        "document_type": "appraisal",
        "file_name": "appraisal.pdf",
        "file_extension": ".pdf",
        "pages": [3, 12],
        "observation_count": 3,
        "signed_url": null
      }
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 5,
    "offset": 0,
    "has_more": false
  }
}

When include_signed_urls=true, document-backed results may include source.signed_url. Signing failures are non-fatal: the result stays in the response with source.signed_url=null and a typed source.signed_url_error such as signing_failed, missing_document_id, or invalid_document_id.

422validation_error
context must not be blankThe request body omits context or sends only whitespace
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
503service_unavailable
Deal data search is temporarily unavailable. Try again shortly.The indexed-data search service is unavailable

Index Observations

POST/api/external/v2/deals/{deal_id}/index/observations

List per-document candidate values behind a deal fact

Each canonical fact returned by Search Index may be backed by multiple observations — one per document our extractors pulled the value from. Use this endpoint to enumerate those observations after a search, then either:

  • show the user where a value came from (file, page range, confidence), or
  • pick an observation_id to promote via Update Index Fact so the canonical value keeps its document provenance.

Provide either sot_id (preferred — scopes to the exact fact behind a single search result) or metric_id (broader — returns observations for that metric across entities, optionally scoped by entity_ref). At least one is required.

Path parameters
deal_idintegerrequired
The deal ID
Request body
sot_idstring
Prefixed SOT id from a search result (e.g. d:5362, a:123:property:690). At least one of sot_id or metric_id is required.
metric_idinteger
Numeric metric definition id (> 0). Use when fetching every observation for a metric across entities.
entity_refstring
Optional entity scoping (e.g. property:690). Intended for use with metric_id; combining with sot_id has no additional effect.
pageinteger
1-based page number. Defaults to 1.
limitinteger
Observations per page. Defaults to 20 and is clamped to 1-200.
include_signed_urlsboolean
When true, document-backed source records may include short-lived signed URLs for inspection or download.
curl -X POST "https://api.lev.com/api/external/v2/deals/101/index/observations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sot_id": "d:5362",
    "limit": 20,
    "include_signed_urls": false
  }'

Response (200):

{
  "request_id": "d4e5f6a7-b8c9-0123-defa-234567890123",
  "timestamp": "2026-05-12T17:45:30Z",
  "data": [
    {
      "id": 9012,
      "metric_key": "deal_financials.in_place_noi",
      "metric_id": 42,
      "value_text": "$1,250,000",
      "value_type": "currency",
      "original_text": "In-place NOI of $1,250,000 as of T-12",
      "context": "Page 3 of the appraisal reports trailing twelve month NOI.",
      "summary": "In-place NOI is $1.25M based on the appraisal.",
      "period_type": "point_in_time",
      "period_value": null,
      "entity_type": "deal",
      "entity_id": null,
      "entity_ref": "deal:101",
      "group_ref": null,
      "category_id": 5,
      "confidence": 0.91,
      "weight": 10,
      "source": {
        "type": "document",
        "document_id": 99,
        "document_type": "appraisal",
        "file_name": "appraisal.pdf",
        "file_extension": ".pdf",
        "pages": [3],
        "observation_count": 1,
        "signed_url": null
      }
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 20,
    "offset": 0,
    "has_more": false
  }
}

When include_signed_urls=true, document-backed results may include source.signed_url. Signing failures are non-fatal and follow the same source.signed_url_error convention as Search Index.

422validation_error
Provide at least one of sot_id or metric_idThe request body omits both sot_id and metric_id
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
503service_unavailable
Deal observations are temporarily unavailable. Please try again shortly.The indexed-data service is unavailable

Update Index Fact

PATCH/api/external/v2/deals/{deal_id}/index/facts

Update a single canonical deal fact value

Use this to change the canonical value behind a fact returned by Search Index. Provide exactly one of:

  • value — a direct, user-supplied replacement. Strips document provenance.
  • observation_id — promote an existing observation returned by Index Observations. Preferred when the user is choosing among extracted values, because the new canonical value keeps its source document, page range, and confidence.

Editability is enforced server-side. Some facts (for example most property-canonical fields and certain sponsor financials) cannot be changed through this endpoint and will return a 422 — even if a prior search result hinted otherwise. There is no version history: the last write wins.

Path parameters
deal_idintegerrequired
The deal ID
Request body
sot_idstringrequired
Prefixed SOT id from a search result (e.g. d:5362, a:123:property:690). Identifies the fact to update.
valuestring
Free-text replacement value. Provide exactly one of value or observation_id.
observation_idinteger
Observation id (> 0) to promote as the new canonical value. Returned by /index/observations.
curl -X PATCH "https://api.lev.com/api/external/v2/deals/101/index/facts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sot_id": "d:5362",
    "observation_id": 9012
  }'

Response (200):

{
  "request_id": "e5f6a7b8-c9d0-1234-efab-345678901234",
  "timestamp": "2026-05-12T17:50:12Z",
  "data": {
    "id": "5362",
    "sot_id": 5362,
    "metric_key": "deal_financials.in_place_noi",
    "metric_id": 42,
    "value_text": "$1,250,000",
    "value_type": "currency",
    "period_type": "point_in_time",
    "period_value": null,
    "entity_type": "deal",
    "entity_id": null,
    "entity_ref": "deal:101",
    "group_ref": null,
    "category_id": 5,
    "source_type": "document",
    "source_id": "99",
    "observation_id": 9012,
    "weight": 10,
    "origin": "promoted_observation",
    "editable": true
  }
}
422validation_error
Provide exactly one of value or observation_idThe request body omits both, or sends both, of value and observation_id
422validation_error
Metric is not editableThe fact targets a metric flagged as non-editable upstream
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
503service_unavailable
Deal fact update is temporarily unavailable. Please try again shortly.The indexed-data service is unavailable or returned a malformed payload

Metric Definitions

GET/api/external/v2/deals/{deal_id}/index/metric-definitions

List the metric definitions that can be recorded on a deal

Returns the catalog of metrics you can record on a deal — the metric_id and value_type you need when calling Insert Index Facts. Use it to discover what's recordable (for example NOI, occupancy, or purchase price) before writing a new fact. To change a fact a deal already has, prefer Search Index to find it, then Update Index Fact.

The catalog is shared across deals, not deal-specific — every deal sees the same definitions. Results are paginated and default to 100 per page.

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
metric_labelstring
Case-insensitive search term to filter by metric label (for example, noi).
category_idinteger
Filter to a single metric category id (greater than 0).
pageinteger
1-based page number. Defaults to 1.
limitinteger
Metric definitions per page. Defaults to 100 and is clamped to 1-200.
curl "https://api.lev.com/api/external/v2/deals/101/index/metric-definitions?limit=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "f6a7b8c9-d0e1-2345-fabc-456789012345",
  "timestamp": "2026-06-01T15:13:07Z",
  "data": [
    {
      "id": 136,
      "metric_key": "properties.property_financials.income.in_place_noi",
      "metric_label": "In-Place NOI",
      "value_type": "currency",
      "category_id": 38
    }
  ],
  "pagination": {
    "total": 458,
    "limit": 100,
    "offset": 0,
    "has_more": true
  }
}
422validation_error
limit must be an integerA query parameter (page or limit) is non-numeric or out of range
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
503service_unavailable
Deal metric definitions are temporarily unavailable. Please try again shortly.The metric-definition service is unavailable

Index Entities

GET/api/external/v2/deals/{deal_id}/index/entities

List the entities you can attach recorded facts to

Lists the deal's entities and their entity_ref values — the deal itself plus its properties, sponsor, broker, and team members. Pass an entity_ref to Insert Index Facts to target which entity a recorded value belongs to. The entity_ref must match the metric's entity type: a property metric such as in-place NOI is recorded against a property: ref, not the deal: ref.

This endpoint does not create entities. To add a new property, call Create Deal (properties) or Update Deal (add_properties) — an address is the minimum required field — then read this endpoint again for the new entity_ref.

Path parameters
deal_idintegerrequired
The deal ID
curl "https://api.lev.com/api/external/v2/deals/101/index/entities" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "a7b8c9d0-e1f2-3456-abcd-567890123456",
  "timestamp": "2026-06-01T15:13:07Z",
  "data": [
    {
      "entity_ref": "deal:101",
      "entity_type": "deal",
      "entity_id": 101,
      "group_ref": null,
      "identifying_metrics": [
        {
          "metric_key": "deal.metadata.title",
          "metric_label": "Title",
          "value_text": "2727 Cedar Springs Road, Dallas, TX",
          "support_multiple_values": false
        }
      ]
    },
    {
      "entity_ref": "property:690",
      "entity_type": "property",
      "entity_id": 690,
      "group_ref": null,
      "identifying_metrics": [
        {
          "metric_key": "properties.property_details.identification.address",
          "metric_label": "Address",
          "value_text": "2727 Cedar Springs Road, Dallas, TX",
          "support_multiple_values": true
        }
      ]
    }
  ],
  "pagination": {
    "total": 2,
    "limit": 2,
    "offset": 0,
    "has_more": false
  }
}
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
503service_unavailable
Deal entities are temporarily unavailable. Please try again shortly.The entity-discovery service is unavailable

Insert Index Facts

POST/api/external/v2/deals/{deal_id}/index/facts

Record one or more user-supplied metric values on a deal

This is the default write path for user-supplied metric values — including when you're replacing a value the deal already has. Each insert creates or reuses a user-input observation and promotes it as the canonical value when supported.

The flow has three steps: discover the metric with Metric Definitions, discover the target entity with Index Entities, then post one or more metric_id + value pairs. Provide an entity_ref that matches the metric's entity type — a property metric needs a property: ref. On a single-property deal the entity can be inferred, but sending the explicit entity_ref is recommended.

To correct one existing fact (for example, fixing the NOI to $1.25M), use Update Index Fact instead — it targets a specific sot_id directly.

Path parameters
deal_idintegerrequired
The deal ID
Request body
valuesarrayrequired
One or more metric values to record. Must contain at least one item.
values[].metric_idintegerrequired
Metric definition id (greater than 0) from /index/metric-definitions.
values[].valuestringrequired
The value to record. Must not be blank.
values[].entity_refstring
Entity to attach the value to, from /index/entities (for example, property:690). Must match the metric's entity type.
values[].group_refstring
Groups several submitted values under the same not-yet-created entity. Use only when no entity_ref is available.
curl -X POST "https://api.lev.com/api/external/v2/deals/101/index/facts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "values": [
      {
        "metric_id": 136,
        "value": "$1,250,000",
        "entity_ref": "property:690"
      }
    ]
  }'

Response (200):

results reports the outcome of each submitted value in request order; metric_sot_values aggregates the SOTs that were written. Each results[].sot has the same shape as a metric_sot_values entry.

{
  "request_id": "955b958f-55d6-42cc-a0f8-c600ce69f517",
  "timestamp": "2026-06-01T15:19:34Z",
  "data": {
    "success": true,
    "error": null,
    "metric_sot_values": [
      {
        "id": "a:136:property:690",
        "sot_id": null,
        "metric_key": "properties.property_financials.income.in_place_noi",
        "metric_id": 136,
        "value_text": "$1,250,000",
        "value_type": "currency",
        "period_type": "none",
        "period_value": null,
        "entity_type": "property",
        "entity_id": 690,
        "entity_ref": "property:690",
        "group_ref": null,
        "category_id": 38,
        "source_type": "user_input",
        "source_id": null,
        "observation_id": 17194,
        "weight": 100,
        "origin": "user",
        "editable": null
      }
    ],
    "results": [
      {
        "index": 0,
        "metric_id": 136,
        "success": true,
        "error": null,
        "sot": {
          "id": "a:136:property:690",
          "sot_id": null,
          "metric_key": "properties.property_financials.income.in_place_noi",
          "metric_id": 136,
          "value_text": "$1,250,000",
          "value_type": "currency",
          "period_type": "none",
          "period_value": null,
          "entity_type": "property",
          "entity_id": 690,
          "entity_ref": "property:690",
          "group_ref": null,
          "category_id": 38,
          "source_type": "user_input",
          "source_id": null,
          "observation_id": 17194,
          "weight": 100,
          "origin": "user",
          "editable": null
        }
      }
    ]
  }
}
Inserts return 200 even when values fail

A request can partially or fully fail while still returning HTTP 200. Always check the top-level success and each results[].error. For example, recording a property metric against a deal: ref returns success: false, an Invalid entity_ref for metric entity type error on that item, and an empty metric_sot_values.

422validation_error
values must contain at least one itemThe values array is empty or missing
422validation_error
value must not be blankA submitted value is empty or whitespace-only
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Deal not foundThe deal_id doesn't exist, isn't accessible, or you lack write access
503service_unavailable
Deal fact insert is temporarily unavailable. Please try again shortly.The indexed-data service is unavailable

List Vaults

GET/api/external/v2/deals/{deal_id}/vaults

List a deal's vaults — its private Resources area and any shared Deal Rooms

Lists the vaults on a deal. Every deal has one private Resources vault for its own working files, plus zero or more shared vaults — the Deal Rooms the borrower shares with other parties. Use this to see how a deal's documents are organized into rooms before browsing files with List Documents.

Each vault reports its document_count. Results are ordered Resources first, then the deal's primary Deal Room (is_default: true), then any other shared vaults.

Path parameters
deal_idintegerrequired
The deal ID
curl "https://api.lev.com/api/external/v2/deals/101/vaults" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "5f3c2a1e-9b7d-4c2a-8f1e-2d6b0a4c7e91",
  "timestamp": "2026-06-09T17:59:05Z",
  "data": [
    {
      "id": 41,
      "type": "resources",
      "title": "Deal Resources",
      "is_default": false,
      "document_count": 3
    },
    {
      "id": 42,
      "type": "shared",
      "title": "Deal Room",
      "is_default": true,
      "document_count": 2
    },
    {
      "id": 57,
      "type": "shared",
      "title": "Closing",
      "is_default": false,
      "document_count": 4
    }
  ],
  "pagination": {
    "total": 3,
    "limit": 3,
    "offset": 0,
    "has_more": false
  }
}

The type is the structural category — resources or shared — and title carries the human name. Only the default shared vault is the deal's primary Deal Room; other shared vaults are user-named for their own purpose (a per-lender room, Closing, and so on), so present the title, not the raw type. Pass a vault's id as the vault_id query parameter on List Documents to browse just that one. See the Vault Object for the full field reference.

401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: documents:readThe credential does not include the documents:read scope
404not_found
Deal not foundThe deal_id doesn't exist or isn't accessible to the authenticated user

List Documents

GET/api/external/v2/deals/{deal_id}/documents

List a deal's uploaded documents across all of its vaults

Lists files uploaded to the deal — across its private Resources vault and any shared Deal Rooms. This is the deal-document browse surface for rent rolls, appraisals, budgets, closing documents, and other uploaded files. It is separate from generated memos and deal books, which are returned by List Memos.

By default the listing spans every vault on the deal, and each document is tagged with the vault it lives in. A file shared into more than one vault appears once per vault. Pass vault_id to drill into a single vault — get the ids from List Vaults.

The list returns metadata only. It does not include signed download URLs. Fetch a single document with Get Document, then use Download Document when you need a fresh file link.

Explicit filters only

This endpoint supports search, extension, folder_id, and vault_id. It intentionally does not accept generic filter[...] parameters.

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
limitinteger
Documents per page. Defaults to 50 and is clamped to 1-200.
cursorstring
Cursor for the next page.
searchstring
Case-insensitive substring match on the document file name.
extensionstring
Filter to one file extension, e.g. `pdf` or `xlsx`. Omit the leading dot.
folder_idinteger
Only documents directly inside this folder. Omit to span the whole vault.
vault_idinteger
Only documents in this vault (a Deal Room or Resources). Get ids from [List Vaults](#list-vaults). Omit to span every vault on the deal.
fieldsstring
Comma-separated fields to include. `id` and `vault` are always included.
curl "https://api.lev.com/api/external/v2/deals/101/documents?limit=20&extension=pdf" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "7b61eb1f-33e8-4b10-8891-90c6e6f5e768",
  "timestamp": "2026-06-08T15:45:12Z",
  "data": [
    {
      "id": 17,
      "file_name": "rent-roll.pdf",
      "extension": "pdf",
      "size_bytes": 98765,
      "folder_path": "Financials/2024",
      "uploaded_at": "2026-06-01T10:00:00",
      "vault": { "id": 41, "type": "resources", "title": "Deal Resources" }
    },
    {
      "id": 21,
      "file_name": "appraisal.pdf",
      "extension": "pdf",
      "size_bytes": 1452200,
      "folder_path": null,
      "uploaded_at": "2026-06-03T14:18:27",
      "vault": { "id": 42, "type": "shared", "title": "Deal Room" }
    }
  ],
  "pagination": {
    "total": 2,
    "limit": 20,
    "cursor": null,
    "has_more": false,
    "next_cursor": null
  }
}

Each document carries a vault tag — the Vault Object (id, type, title) for the vault it lives in. An accessible deal with no documents returns an empty list, not a 404. Documents that are rejected during review are excluded from list, detail, and download responses.

401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: documents:readThe credential does not include the documents:read scope
404not_found
Deal not foundThe deal_id doesn't exist or isn't accessible to the authenticated user
404not_found
Vault not foundA vault_id is provided that doesn't belong to this deal
422validation_error
This endpoint does not accept filter parametersA generic filter[...] query parameter is provided

Get Document

GET/api/external/v2/deals/{deal_id}/documents/{document_id}

Fetch metadata for one uploaded document

Returns one uploaded document's metadata, including the vault it lives in. The document_id is the id returned by List Documents. The document is resolved across all of the requested deal's vaults — its Resources vault and any Deal Rooms.

Path parameters
deal_idintegerrequired
The deal ID
document_idintegerrequired
The document ID from the list endpoint
Query parameters
fieldsstring
Comma-separated fields to include. `id` is always included.
curl "https://api.lev.com/api/external/v2/deals/101/documents/17" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "ae1df8ee-c7c9-4ed0-82d2-19c4ec042ac4",
  "timestamp": "2026-06-08T15:46:18Z",
  "data": {
    "id": 17,
    "file_name": "rent-roll.pdf",
    "extension": "pdf",
    "size_bytes": 98765,
    "folder_path": "Financials/2024",
    "uploaded_at": "2026-06-01T10:00:00",
    "vault": { "id": 41, "type": "resources", "title": "Deal Resources" }
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: documents:readThe credential does not include the documents:read scope
404not_found
Document not foundThe document_id doesn't exist on the deal, is rejected, or isn't readable by the authenticated user

Download Document

GET/api/external/v2/deals/{deal_id}/documents/{document_id}/download

Fetch a short-lived signed download link for one uploaded document

Returns a signed S3 download URL for one uploaded document. The document is resolved across all of the deal's vaults, and the API re-checks that it belongs to the requested deal before signing, so a document from another deal returns 404 even if the account owns both deals.

Signed URLs expire after about 15 minutes. Request a fresh download link when the user is ready to open the file, and store document IDs rather than signed URLs in your system.

Path parameters
deal_idintegerrequired
The deal ID
document_idintegerrequired
The document ID from the list endpoint
curl "https://api.lev.com/api/external/v2/deals/101/documents/17/download" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "9fe1bfe1-b5c5-4a5f-8c7d-2766cf67a607",
  "timestamp": "2026-06-08T15:47:08Z",
  "data": {
    "file_name": "rent-roll.pdf",
    "download_url": "https://signed-s3-url.example/rent-roll.pdf",
    "expires_in": 900
  }
}
Signed document links expire

download_url is a short-lived bearer link to the file bytes. Fetch it when you need a fresh link, present it as a clickable file-name link, and avoid displaying the raw URL in chat or UI surfaces.

401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: documents:readThe credential does not include the documents:read scope
404not_found
Document not foundThe document_id doesn't exist on the deal, is rejected, or isn't readable by the authenticated user

List Checklists

GET/api/external/v2/deals/{deal_id}/checklists

List a deal's checklists — one per shared Deal Room, with sections, tasks, document types, and task-linked files

Lists the checklists on a deal: the items to collect, review, or complete in each Deal Room. Checklists live on the deal's shared vaults. Each Deal Room can carry one checklist, and a deal with several Deal Rooms can have several checklists. The deal's private Resources vault does not have a checklist. Results are ordered with the primary Deal Room's checklist first.

Use the task-level document_types array to see what type of document a request expects. Use the task-level files array to see which uploaded files are already linked to that task. A task with no files can still be complete if a user marked it complete manually, so use both files and the completion fields (status, is_completed) when reporting what is satisfied or outstanding.

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
vault_idinteger
Only return the checklist for one shared Deal Room. Omit to return every Deal Room checklist on the deal.
curl "https://api.lev.com/api/external/v2/deals/101/checklists" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "fa8d1a1e-4e9a-4c82-b68e-44e8db5b3a0c",
  "timestamp": "2026-06-15T18:04:22Z",
  "data": [
    {
      "id": 11,
      "vault": {
        "id": 42,
        "type": "shared",
        "title": "Deal Room"
      },
      "sections": [
        {
          "id": 21,
          "name": "Financials",
          "position": 1,
          "start_date": "2026-06-01",
          "end_date": null,
          "tasks": [
            {
              "id": 301,
              "title": "Rent roll",
              "description": "Trailing 12 months",
              "status": "reviewing",
              "is_completed": false,
              "position": 1,
              "due_date": "2026-07-01",
              "role": "borrower",
              "assignee": {
                "id": 9,
                "first_name": "Ada",
                "last_name": "Lovelace",
                "email": "ada@example.com"
              },
              "assigned_team": {
                "id": 8256,
                "type": "account",
                "name": "Borrower Team"
              },
              "collaborators": [
                {
                  "id": null,
                  "email": "outside@example.com"
                }
              ],
              "document_types": [
                {
                  "id": 15,
                  "name": "Rent roll"
                }
              ],
              "files": [
                {
                  "vault_resource_id": 6001,
                  "document_id": 901,
                  "name": "Rent roll.xlsx",
                  "origin": "auto_match"
                }
              ],
              "subtasks": []
            }
          ]
        }
      ],
      "tasks": []
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 1,
    "offset": 0,
    "has_more": false
  }
}

Sections and tasks come back in display order (position ascending), matching the checklist as it appears in Lev. See the Checklist Object, Checklist Section Object, and Checklist Task Object for the full field reference.

401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: checklists:readThe credential does not include the checklists:read scope
404not_found
Deal not foundThe deal_id doesn't exist or isn't accessible to the authenticated user

List Memos

GET/api/external/v2/deals/{deal_id}/memos

List a deal's generated memos (deal books)

Lists the memos — AI-generated deal books — for a deal. Returns both published memos and unpublished drafts, so you can support preview-your-own-work flows. Each row carries status (published or draft) and published_at to disambiguate, plus updated_at (last-modified) and created_by ({id, name} — who made the memo). Published memos come first (most recently published), then drafts (most recently updated).

PDF download links are omitted here — fetch a single memo with Get Memo for signed pdf_url links. Each row's pdf_ready flag tells you whether a downloadable PDF has rendered yet.

By default the listing spans every vault on the deal, and each memo is tagged with the vaults it lives in. A memo can sit in more than one vault. Pass vault_id to return only the memos in a single vault — get the ids from List Vaults.

Narrow the list server-side with search (a case-insensitive title substring) and the filter[title] (exact title), filter[status], filter[memo_type], and filter[pdf_ready] parameters. Filters compose, and pagination reflects the filtered set. There is no sort control — the published-first ordering is fixed.

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
limitinteger
Memos per page. Defaults to 50 and is clamped to 1-200.
offsetinteger
0-based index of the first memo to return. Defaults to 0.
searchstring
Case-insensitive substring match on the memo title.
filter[title]string
Exact match on the full memo title. Use search for a substring match instead.
filter[status]string
Filter by publish state: draft or published.
filter[memo_type]string
Filter by memo type: debt_financing_om, credit_memo, investment_sales, debt_brokerage, equity_raise, broker_opinion_of_value, investment_committee, invoice, or other.
filter[pdf_ready]boolean
Filter to memos whose downloadable PDF has rendered (true) or not yet (false).
vault_idinteger
Only memos in this vault (a Deal Room or Resources). Get ids from [List Vaults](#list-vaults). Omit to span every vault on the deal.
curl "https://api.lev.com/api/external/v2/deals/101/memos" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "43f2c567-57e4-4fac-8044-b22e01ec562c",
  "timestamp": "2026-06-02T17:25:28Z",
  "data": [
    {
      "uuid": "f26c0055-b2d3-4ca1-b25e-0ce0bacd0d61",
      "title": "Debt Financing Offering Memorandum",
      "memo_type": "debt_financing_om",
      "status": "published",
      "published_at": "2026-05-27T20:21:26",
      "updated_at": "2026-05-28T14:03:11",
      "created_by": { "id": 4012, "name": "Jordan Avery" },
      "pdf_generation_status": "completed",
      "pdf_ready": true,
      "memo_url": "https://memo.lev.com/acme/deals/101/memos/f26c0055-b2d3-4ca1-b25e-0ce0bacd0d61",
      "vaults": [
        { "id": 42, "type": "shared", "title": "Deal Room" },
        { "id": 57, "type": "shared", "title": "Closing" }
      ]
    },
    {
      "uuid": "8452c954-eedc-44ab-afbd-d86a8b65d007",
      "title": "Investment Sales Offering Memorandum (draft)",
      "memo_type": "investment_sales",
      "status": "draft",
      "published_at": null,
      "updated_at": "2026-06-01T09:12:40",
      "created_by": { "id": 4012, "name": "Jordan Avery" },
      "pdf_generation_status": null,
      "pdf_ready": false,
      "memo_url": "https://memo.lev.com/acme/deals/101/memos/8452c954-eedc-44ab-afbd-d86a8b65d007",
      "vaults": []
    }
  ],
  "pagination": {
    "total": 2,
    "limit": 50,
    "offset": 0,
    "has_more": false
  }
}

Each memo carries a vaults array — the Vault Object (id, type, title) for every vault it belongs to. The set is scoped to the vaults your credential can see: a vault you can't access is left out, and a memo in no vault you can see returns vaults: [].

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 Memo

GET/api/external/v2/deals/{deal_id}/memos/{memo_uuid}

Fetch one memo with signed PDF download links

Returns one memo — published or draft — with signed PDF links. pdf_url points at the variant named by quality (default original); pdf_versions lists every rendered variant.

pdf_url is null and pdf_versions is empty when the memo has no rendered variant — common for drafts that have never been previewed (pdf_ready: false).

The vaults array tags the memo with each Vault Object it belongs to — a memo can be in more than one. The set is scoped to the vaults your credential can see, so it is empty when the memo is in no vault you can access.

Path parameters
deal_idintegerrequired
The deal ID
memo_uuidstringrequired
The memo's UUID, from the `uuid` field on a List Memos row.
Query parameters
qualitystring
Which rendered variant `pdf_url` points at: `original` (default), `high`, `medium`, or `low`. An unknown value returns 400.
curl "https://api.lev.com/api/external/v2/deals/101/memos/f26c0055-b2d3-4ca1-b25e-0ce0bacd0d61?quality=original" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "69628f7c-3577-407a-9816-fd90942381f9",
  "timestamp": "2026-06-02T17:25:56Z",
  "data": {
    "uuid": "f26c0055-b2d3-4ca1-b25e-0ce0bacd0d61",
    "title": "Debt Financing Offering Memorandum",
    "memo_type": "debt_financing_om",
    "status": "published",
    "published_at": "2026-05-27T20:21:26",
    "updated_at": "2026-05-28T14:03:11",
    "created_by": { "id": 4012, "name": "Jordan Avery" },
    "pdf_generation_status": "completed",
    "pdf_ready": true,
    "memo_url": "https://memo.lev.com/acme/deals/101/memos/f26c0055-b2d3-4ca1-b25e-0ce0bacd0d61",
    "vaults": [
      { "id": 42, "type": "shared", "title": "Deal Room" },
      { "id": 57, "type": "shared", "title": "Closing" }
    ],
    "pdf_url": "https://…signed-s3-url…",
    "pdf_versions": [
      { "quality": "original", "status": "completed", "pdf_url": "https://…signed-s3-url…" },
      { "quality": "high", "status": "completed", "pdf_url": "https://…signed-s3-url…" },
      { "quality": "medium", "status": "completed", "pdf_url": "https://…signed-s3-url…" },
      { "quality": "low", "status": "completed", "pdf_url": "https://…signed-s3-url…" }
    ]
  }
}
Signed PDF links expire

pdf_url (and each pdf_versions[].pdf_url) is a short-lived signed link. Fetch the memo when you need a fresh link rather than storing it, and don't display the raw URL.

400validation_error
Invalid quality: bogus. Allowed: original, high, medium, lowThe quality query parameter isn't one of the allowed values
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Memo not foundThe memo_uuid doesn't exist on the deal, or isn't readable by the authenticated user

List Deal Notes

GET/api/external/v2/deals/{deal_id}/notes

List notes logged on a deal

Lists the free-text notes logged on a deal — call summaries, lender conversations, and other human-written commentary. Notes are returned oldest first; walk the next_cursor in the response to reach the most recent. Internal or private notes are never returned.

For underwriting facts and where a value came from, use the deal index (Search Index) — notes are commentary, not indexed facts.

Path parameters
deal_idintegerrequired
The deal ID
Query parameters
limitinteger
Results per page (1–200, default 50)
cursorstring
Cursor for next page
curl "https://api.lev.com/api/external/v2/deals/101/notes" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "43f2c567-57e4-4fac-8044-b22e01ec562c",
  "timestamp": "2026-06-08T17:25:28Z",
  "data": [
    {
      "id": 7340,
      "text": "Lender call went well — they're comfortable at 65% LTV, want updated rent roll.",
      "created_by": {
        "id": 88,
        "name": "Dana Lender"
      },
      "created_at": "2026-06-08T10:00:00Z",
      "updated_at": "2026-06-08T10:00:00Z"
    }
  ],
  "pagination": {
    "total": 1,
    "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

Create Deal Note

POST/api/external/v2/deals/{deal_id}/notes

Add a note to a deal

Logs a free-text note on a deal. The note is attributed to the API key's user and appears alongside notes written in the Lev web app. Simple HTML formatting is preserved; scripts and other unsafe markup are stripped.

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

Path parameters
deal_idintegerrequired
The deal ID
Request body
textstringrequired
Note text. Must be non-empty.
curl -X POST "https://api.lev.com/api/external/v2/deals/101/notes" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"text": "Lender call went well — they want an updated rent roll."}'

Response (201):

{
  "request_id": "d0e1f2a3-b4c5-6789-3456-890123456789",
  "timestamp": "2026-06-08T15:30:45Z",
  "data": {
    "id": 7340,
    "text": "Lender call went well — they want an updated rent roll.",
    "created_by": {
      "id": 88,
      "name": "Dana Lender"
    },
    "created_at": "2026-06-08T15:30:45Z",
    "updated_at": "2026-06-08T15:30:45Z"
  }
}
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
422validation_error
text must not be blankThe request omits text or sends an empty string

Update Deal Note

PATCH/api/external/v2/deals/{deal_id}/notes/{note_id}

Edit a deal note

Replaces the text of a note logged on a deal. Requires the deals:write scope. Use the id returned by List Deal Notes or Create Deal Note as note_id.

Only notes the authenticated user created and can still write are editable. Notes on another deal, hidden or private notes, and notes the user does not own return 404 Not Found.

Supports the Idempotency-Key header to make retries safe.

Path parameters
deal_idintegerrequired
The deal ID
note_idintegerrequired
The note ID
Request body
textstringrequired
Replacement note text. Must be non-empty.
curl -X PATCH "https://api.lev.com/api/external/v2/deals/101/notes/7340" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"text": "Lender call went well — they want an updated rent roll and trailing 12."}'

Response (200):

{
  "request_id": "90d7bfc2-ff5e-4b4e-9c77-7987957fd6a7",
  "timestamp": "2026-06-19T15:30:45Z",
  "data": {
    "id": 7340,
    "text": "Lender call went well — they want an updated rent roll and trailing 12.",
    "created_by": {
      "id": 88,
      "name": "Dana Lender"
    },
    "created_at": "2026-06-08T15:30:45Z",
    "updated_at": "2026-06-19T15:30:45Z"
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Deal or note not foundThe deal_id or note_id doesn't exist, doesn't match, isn't externally visible, or isn't writable by the authenticated user
400bad_request
text cannot be emptyThe supplied text becomes empty after sanitization
422validation_error
text must not be blankThe request omits text or sends an empty string

Delete Deal Note

DELETE/api/external/v2/deals/{deal_id}/notes/{note_id}

Permanently delete a deal note

Permanently deletes a note logged on a deal. Requires the deals:write scope. Use the id returned by List Deal Notes or Create Deal Note as note_id.

Only notes the authenticated user created and can still write are deletable. Notes on another deal, hidden or private notes, and notes the user does not own return 404 Not Found.

Path parameters
deal_idintegerrequired
The deal ID
note_idintegerrequired
The note ID
curl -X DELETE "https://api.lev.com/api/external/v2/deals/101/notes/7340" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "2c23bb16-8a8c-4a20-8ec0-9af5f555c84c",
  "timestamp": "2026-06-19T15:30:45Z",
  "data": {
    "deleted": true
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Deal or note not foundThe deal_id or note_id doesn't exist, doesn't match, isn't externally visible, or isn't writable by the authenticated user

List Checklist Task Notes

GET/api/external/v2/checklist-tasks/{task_id}/notes

List comments on a checklist task

Lists the comments on a checklist task — the borrower-portal "comments" that appear in the task's activity feed. A checklist task is a single diligence item (for example, a document request) inside a Deal Room checklist. These are the same comments your team and the borrower post in the portal: reading here returns that thread, and posting is equivalent to commenting on the item in the Lev web app.

Comments are returned oldest first; walk the next_cursor in the response to reach the most recent. Internal or private notes are never returned.

Path parameters
task_idintegerrequired
The checklist task ID
Query parameters
limitinteger
Results per page (1–200, default 50)
cursorstring
Cursor for next page
curl "https://api.lev.com/api/external/v2/checklist-tasks/4821/notes" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "43f2c567-57e4-4fac-8044-b22e01ec562c",
  "timestamp": "2026-06-08T17:25:28Z",
  "data": [
    {
      "id": 9120,
      "text": "Uploaded the latest rent roll — let me know if you also need the prior year.",
      "created_by": {
        "id": 88,
        "name": "Dana Lender"
      },
      "created_at": "2026-06-08T10:00:00Z",
      "updated_at": "2026-06-08T10:00:00Z"
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 50,
    "has_more": false,
    "next_cursor": null
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Checklist task not foundThe task_id doesn't exist or isn't accessible to the authenticated user

Create Checklist Task Note

POST/api/external/v2/checklist-tasks/{task_id}/notes

Add a comment to a checklist task

Posts a comment on a checklist task. The comment is attributed to the API key's user and is borrower-visible — it surfaces in the task's portal activity feed exactly like a comment typed there by you or the borrower. Simple HTML formatting is preserved; scripts and other unsafe markup are stripped.

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

Path parameters
task_idintegerrequired
The checklist task ID
Request body
textstringrequired
Comment text. Must be non-empty.
curl -X POST "https://api.lev.com/api/external/v2/checklist-tasks/4821/notes" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"text": "Uploaded the latest rent roll — let me know if you also need the prior year."}'

Response (201):

{
  "request_id": "d0e1f2a3-b4c5-6789-3456-890123456789",
  "timestamp": "2026-06-08T15:30:45Z",
  "data": {
    "id": 9120,
    "text": "Uploaded the latest rent roll — let me know if you also need the prior year.",
    "created_by": {
      "id": 88,
      "name": "Dana Lender"
    },
    "created_at": "2026-06-08T15:30:45Z",
    "updated_at": "2026-06-08T15:30:45Z"
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Checklist task not foundThe task_id doesn't exist or isn't accessible to the authenticated user
422validation_error
text must not be blankThe request omits text or sends an empty string

Update Checklist Task Note

PATCH/api/external/v2/checklist-tasks/{task_id}/notes/{note_id}

Edit a checklist task comment

Replaces the text of a comment on a checklist task. Requires the checklists:write scope. Use the id returned by List Checklist Task Notes or Create Checklist Task Note as note_id.

Only comments the authenticated user created and can still write are editable. Comments on another checklist task, hidden or private comments, and comments the user does not own return 404 Not Found.

Supports the Idempotency-Key header to make retries safe.

Path parameters
task_idintegerrequired
The checklist task ID
note_idintegerrequired
The note ID
Request body
textstringrequired
Replacement comment text. Must be non-empty.
curl -X PATCH "https://api.lev.com/api/external/v2/checklist-tasks/4821/notes/9120" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"text": "Uploaded the latest rent roll and prior-year version."}'

Response (200):

{
  "request_id": "90d7bfc2-ff5e-4b4e-9c77-7987957fd6a7",
  "timestamp": "2026-06-19T15:30:45Z",
  "data": {
    "id": 9120,
    "text": "Uploaded the latest rent roll and prior-year version.",
    "created_by": {
      "id": 88,
      "name": "Dana Lender"
    },
    "created_at": "2026-06-08T15:30:45Z",
    "updated_at": "2026-06-19T15:30:45Z"
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Checklist task or note not foundThe task_id or note_id doesn't exist, doesn't match, isn't externally visible, or isn't writable by the authenticated user
400bad_request
text cannot be emptyThe supplied text becomes empty after sanitization
422validation_error
text must not be blankThe request omits text or sends an empty string

Delete Checklist Task Note

DELETE/api/external/v2/checklist-tasks/{task_id}/notes/{note_id}

Permanently delete a checklist task comment

Permanently deletes a comment on a checklist task. Requires the checklists:write scope. Use the id returned by List Checklist Task Notes or Create Checklist Task Note as note_id.

Only comments the authenticated user created and can still write are deletable. Comments on another checklist task, hidden or private comments, and comments the user does not own return 404 Not Found.

Path parameters
task_idintegerrequired
The checklist task ID
note_idintegerrequired
The note ID
curl -X DELETE "https://api.lev.com/api/external/v2/checklist-tasks/4821/notes/9120" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response (200):

{
  "request_id": "2c23bb16-8a8c-4a20-8ec0-9af5f555c84c",
  "timestamp": "2026-06-19T15:30:45Z",
  "data": {
    "deleted": true
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
404not_found
Checklist task or note not foundThe task_id or note_id doesn't exist, doesn't match, isn't externally visible, or isn't writable by the authenticated user

Create Checklist Task

POST/api/external/v2/checklist-tasks

Add a task to a deal's checklist

Creates a checklist task — a document request or to-do tracked on the deal, such as collecting the trailing-12 operating statements. Anchor the task under exactly one parent: provide one of section_id (inside a section), checklist_id (at the checklist root, outside any section), or parent_task_id (a subtask, one level deep). Get those ids from List Checklists.

Returns the created task in the same shape List Checklists returns. Requires the checklists:write scope. Supports the Idempotency-Key header to prevent duplicate creation.

Request body
titlestringrequired
Task title. Must be non-empty.
section_idinteger
Add the task inside this checklist section. Provide exactly one of section_id, checklist_id, or parent_task_id.
checklist_idinteger
Add the task at the checklist root, outside any section. Provide exactly one of section_id, checklist_id, or parent_task_id.
parent_task_idinteger
Add the task as a subtask of this task (one level deep). Provide exactly one of section_id, checklist_id, or parent_task_id.
descriptionstring
Optional longer detail.
statusstring
Initial review state: to_do, requested, reviewing, updates_needed, approved, or cancelled. Defaults to to_do.
assigned_user_idinteger
Lev user id to assign. Must be an active teammate in your account.
due_datestring
Due date (ISO 8601, YYYY-MM-DD).
document_type_idsarray
Expected document type ids for the request.
curl -X POST "https://api.lev.com/api/external/v2/checklist-tasks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "title": "Trailing-12 operating statements",
    "section_id": 21,
    "description": "From the sponsor",
    "due_date": "2026-07-15",
    "document_type_ids": [15]
  }'

Response (201):

{
  "request_id": "b1c2d3e4-f5a6-7890-1234-567890abcdef",
  "timestamp": "2026-06-23T15:30:45Z",
  "data": {
    "id": 412,
    "title": "Trailing-12 operating statements",
    "description": "From the sponsor",
    "status": "to_do",
    "is_completed": false,
    "position": 4,
    "due_date": "2026-07-15",
    "role": null,
    "assignee": null,
    "assigned_team": null,
    "collaborators": [],
    "document_types": [
      {
        "id": 15,
        "name": "Operating statement"
      }
    ],
    "files": [],
    "subtasks": []
  }
}

See the Checklist Task Object for the full field reference.

401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: checklists:writeThe credential does not include the checklists:write scope
400validation_error
assigned_user_id must belong to an active user in your accountThe assigned_user_id is deactivated or belongs to another account
404not_found
Section, checklist, or parent task not foundThe section_id, checklist_id, or parent_task_id doesn't exist or isn't accessible to the authenticated user
422validation_error
Provide exactly one of section_id, checklist_id, or parent_task_idThe request omits the anchor, sends more than one, or sends a blank title

Update Checklist Task

PATCH/api/external/v2/checklist-tasks/{task_id}

Change a checklist task's fields

Edits an existing checklist task — retitle, re-status, reassign, set a due date, or reopen it. Get the task_id from List Checklists. Sends only the fields you provide; omitted fields are left unchanged. Send null for description, assigned_user_id, due_date, or document_type_ids to clear them.

To mark a task complete use Complete Checklist Task — it also approves the task's attached files. Here is_completed accepts false only, to reopen a completed task. Requires the checklists:write scope. Supports the Idempotency-Key header to make retries safe.

Path parameters
task_idintegerrequired
The checklist task ID
Request body
titlestring
New title. Must be non-empty if provided.
descriptionstring|null
New description. Send `null` to clear.
statusstring
New review state: to_do, requested, reviewing, updates_needed, approved, or cancelled.
assigned_user_idinteger|null
New assignee. Must be an active teammate in your account. Send `null` to unassign.
due_datestring|null
New due date (ISO 8601, YYYY-MM-DD). Send `null` to clear.
is_completedboolean
Pass false to reopen a completed task. To mark a task complete use the complete endpoint.
document_type_idsarray|null
Replace the expected document type ids. Send `null` to clear.
curl -X PATCH "https://api.lev.com/api/external/v2/checklist-tasks/301" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"due_date": "2026-07-15", "assigned_user_id": 88}'

Response (200):

{
  "request_id": "c2d3e4f5-a6b7-8901-2345-678901bcdef0",
  "timestamp": "2026-06-23T15:30:45Z",
  "data": {
    "id": 301,
    "title": "Rent roll",
    "description": "Trailing 12 months",
    "status": "reviewing",
    "is_completed": false,
    "position": 1,
    "due_date": "2026-07-15",
    "role": "borrower",
    "assignee": {
      "id": 88,
      "first_name": "Dana",
      "last_name": "Lender",
      "email": "dana@example.com"
    },
    "assigned_team": {
      "id": 8256,
      "type": "account",
      "name": "Borrower Team"
    },
    "collaborators": [],
    "document_types": [
      {
        "id": 15,
        "name": "Rent roll"
      }
    ],
    "files": [],
    "subtasks": []
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: checklists:writeThe credential does not include the checklists:write scope
400validation_error
assigned_user_id must belong to an active user in your accountThe assigned_user_id is deactivated or belongs to another account
404not_found
Checklist task not foundThe task_id doesn't exist or isn't accessible to the authenticated user
422validation_error
is_completed accepts false only; to mark a task complete use the complete endpointThe request sets is_completed to true or sends a blank title

Complete Checklist Task

POST/api/external/v2/checklist-tasks/{task_id}/complete

Mark a checklist task complete

Marks a checklist task done — the equivalent of checking it off in the deal's checklist. Completing also moves the task to approved status and approves any pending files already attached to it, matching the in-app action. Get the task_id from List Checklists.

The body is empty. The action is idempotent: completing an already-complete task leaves it complete. To reopen a completed task use Update Checklist Task with is_completed set to false. Requires the checklists:write scope. Supports the Idempotency-Key header to make retries safe.

Path parameters
task_idintegerrequired
The checklist task ID
curl -X POST "https://api.lev.com/api/external/v2/checklist-tasks/301/complete" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000"

Response (200):

{
  "request_id": "d3e4f5a6-b7c8-9012-3456-789012cdef01",
  "timestamp": "2026-06-23T15:30:45Z",
  "data": {
    "id": 301,
    "title": "Rent roll",
    "description": "Trailing 12 months",
    "status": "approved",
    "is_completed": true,
    "position": 1,
    "due_date": "2026-07-01",
    "role": "borrower",
    "assignee": {
      "id": 88,
      "first_name": "Dana",
      "last_name": "Lender",
      "email": "dana@example.com"
    },
    "assigned_team": {
      "id": 8256,
      "type": "account",
      "name": "Borrower Team"
    },
    "collaborators": [],
    "document_types": [
      {
        "id": 15,
        "name": "Rent roll"
      }
    ],
    "files": [
      {
        "vault_resource_id": 6001,
        "document_id": 901,
        "name": "Rent roll.xlsx",
        "origin": "manually_added"
      }
    ],
    "subtasks": []
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
403forbidden
Missing required scope: checklists:writeThe credential does not include the checklists:write scope
404not_found
Checklist task not foundThe task_id doesn't exist or isn't accessible to the authenticated user

Create Deal

POST/api/external/v2/deals

Create a new deal

Supports the Idempotency-Key header to prevent duplicate creation.

Request body
titlestringrequired
Deal title (1–255 characters)
loan_amountnumber
Requested loan amount
loan_typeLoanType
Loan type enum name, such as construction, heavy_bridge, or permanent
transaction_typeTransactionType
Transaction type enum name, such as acquisition, refinance, or new_construction
business_planBusinessPlanType
Business plan enum name: stabilized, value_add, construction, or land
descriptionstring
Deal description
estimated_close_datestring
Estimated close date (ISO 8601)
pipeline_idsinteger[]
Pipeline IDs to add the deal to
deal_financialsDealFinancialsWrite
Deal-level financial fields to create with the deal
curl -X POST "https://api.lev.com/api/external/v2/deals" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{
    "title": "456 Oak Ave Refinance",
    "loan_amount": 3500000,
    "loan_type": "permanent",
    "transaction_type": "refinance",
    "deal_financials": {
      "purchase_price": 5250000,
      "estimated_value": 5900000,
      "total_cost": 5500000
    }
  }'

Response (201):

{
  "request_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": {
    "id": 205,
    "title": "456 Oak Ave Refinance",
    "loan_amount": 3500000.0,
    "loan_type": "permanent",
    "transaction_type": "refinance",
    "business_plan": null,
    "description": null,
    "estimated_close_date": null,
    "close_date": null,
    "owner_account_id": 56,
    "created_at": "2026-03-20T15:30:45Z",
    "updated_at": "2026-03-20T15:30:45Z",
    "archived": false,
    "archived_at": null
  }
}
401unauthorized
Authentication requiredMissing or invalid Authorization header
422validation_error
title is requiredMissing the required title field in the request body

Update Deal

PATCH/api/external/v2/deals/{deal_id}

Update a deal (partial update)

Path parameters
deal_idintegerrequired
The deal ID

All request body fields are optional. Only provided fields are updated. For deal_financials, omitted nested fields are unchanged and explicit null clears an existing value.

Request body
titlestring
Deal title (min 1 character)
loan_amountnumber
Requested loan amount
loan_typeLoanType
Loan type enum name
transaction_typeTransactionType
Transaction type enum name
business_planBusinessPlanType
Business plan enum name
descriptionstring
Deal description
estimated_close_datestring
Estimated close date (ISO 8601)
deal_financialsDealFinancialsWrite
Deal-level financial fields to update
curl -X PATCH "https://api.lev.com/api/external/v2/deals/101" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "loan_amount": 7500000,
    "deal_financials": {
      "purchase_price": 6500000,
      "estimated_value": null
    }
  }'

Response (200):

{
  "request_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": {
    "id": 101,
    "title": "123 Main St Acquisition",
    "loan_amount": 7500000.0,
    "loan_type": "heavy_bridge",
    "transaction_type": "acquisition",
    "business_plan": "value_add",
    "description": "Mixed-use acquisition in downtown Chicago — updated loan amount",
    "estimated_close_date": "2026-07-15",
    "close_date": null,
    "owner_account_id": 56,
    "created_at": "2026-01-15T10:00:00Z",
    "updated_at": "2026-03-20T15:30:45Z",
    "archived": false,
    "archived_at": 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

Delete Deal

DELETE/api/external/v2/deals/{deal_id}

Archive (soft-delete) a deal

Path parameters
deal_idintegerrequired
The deal ID

Response (200):

{
  "request_id": "...",
  "timestamp": "2026-03-20T15:30:45Z",
  "data": {
    "deleted": true
  }
}
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

Document Object

FieldTypeDescription
idintegerUnique document identifier. Use this value in the document detail and download endpoints.
file_namestring|nullOriginal file name.
extensionstring|nullFile extension without the leading dot.
size_bytesinteger|nullFile size in bytes. May be null for older records whose size was not stored.
folder_pathstring|nullSlash-delimited path inside the vault, or null for files at the vault root.
uploaded_atstring|nullUpload timestamp (ISO 8601).
vaultDocumentVaultRefThe vault this document lives in — the compact id, type, title subset of the Vault Object (omits the list-only is_default and document_count). Always present, even under a sparse fields request.

Vault Object

A vault is a container for a deal's documents. Returned by List Vaults, embedded as the vault tag on each Document Object, and listed in the vaults array on each memo (List Memos, Get Memo).

FieldTypeDescription
idintegerUnique vault identifier. Pass as vault_id on List Documents to browse just this vault.
typestringStructural category: resources (the deal's single private working vault) or shared (a vault the borrower can share with other parties). Present the title to users, not this raw value.
titlestring|nullHuman-readable vault name — Deal Resources for the private vault; shared vaults carry names like Deal Room, Closing, or a per-lender room.
is_defaultbooleantrue for the deal's primary Deal Room (its default shared vault). Returned by List Vaults; omitted from the embedded document vault tag.
document_countintegerNumber of documents in the vault. Returned by List Vaults; omitted from the embedded document vault tag.

Checklist Object

A checklist is the to-do and request list inside one Deal Room. Returned by List Checklists, one per shared vault.

FieldTypeDescription
idintegerUnique checklist identifier
vaultChecklistVaultRefThe Deal Room this checklist belongs to: id, type, and title. type is always shared; checklists do not live on the private Resources vault.
sectionsChecklistSection[]Ordered sections, each carrying its own tasks. See the Checklist Section Object.
tasksChecklistTask[]Root-level tasks that sit outside any section, in display order. See the Checklist Task Object.

Checklist Section Object

FieldTypeDescription
idintegerUnique section identifier
namestringSection name
positionintegerDisplay order inside the checklist
start_datestring|nullOptional section start date (ISO 8601)
end_datestring|nullOptional section end date (ISO 8601)
tasksChecklistTask[]The section's tasks in display order. See the Checklist Task Object.

Checklist Task Object

FieldTypeDescription
idintegerUnique task identifier
titlestringTask title
descriptionstring|nullTask description
statusstringReview state: to_do, requested, reviewing, updates_needed, approved, or cancelled.
is_completedbooleanSeparate done flag. A task can be approved but not marked complete.
positionintegerDisplay order inside its section or root task list
due_datestring|nullDue date (ISO 8601)
rolestring|nullRole responsible for the task, such as borrower or lender
assigneeChecklistAssignee|nullThe Lev user assigned to the task, or null when unassigned.
assigned_teamChecklistAssignedTeam|nullThe account, lender, or borrower team assigned to the task. name can be null for stale or out-of-scope team references.
collaboratorsChecklistCollaborator[]People looped into the task. Each carries id and email; id is null for external parties without a Lev account.
document_typesChecklistDocumentType[]Expected document types for the request, such as Appraisal or Rent roll.
filesChecklistTaskFile[]Uploaded files already linked to this task. Each file includes document_id, vault_resource_id, name, and origin.
subtasksChecklistTask[]Nested subtasks, one level deep, in the same task shape.

Deal Object

FieldTypeDescription
idintegerUnique deal identifier
titlestring|nullDeal title
loan_amountnumber|nullRequested loan amount
loan_typeLoanType|nullLoan type enum name
transaction_typeTransactionType|nullTransaction type enum name
business_planBusinessPlanType|nullBusiness plan enum name
descriptionstring|nullDeal description
estimated_close_datestring|nullEstimated close date (ISO 8601)
close_datestring|nullActual close date (ISO 8601)
owner_account_idinteger|nullOwning account ID
created_atstring|nullCreation timestamp (ISO 8601)
updated_atstring|nullLast update timestamp (ISO 8601)
archivedbooleanWhether the deal has been archived. Archiving is separate from pipeline status, so an archived deal keeps its last stage
archived_atstring|nullWhen the deal was archived (ISO 8601), or null when active
financialsobject|nullIncluded when ?include=financials (see Deal Financials)
propertiesarray|nullIncluded when ?include=properties (see Deal Properties)
teamarray|nullIncluded when ?include=team (see Deal Team)
pipelinesarray|nullIncluded when ?include=pipelines. Up to 10 current pipeline rows per deal, each with pipeline_id, status_name, updated_at (see Pipelines)
More in this section