/api/external/v2/deals/{deal_id}/index/factsRecord 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.
deal_idintegerrequiredvaluesarrayrequiredvalues[].metric_idintegerrequiredvalues[].valuestringrequiredvalues[].entity_refstringvalues[].group_refstringcurl -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
}
}
]
}
}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.
validation_errorvalidation_errorunauthorizednot_foundservice_unavailable