curl --request POST \
--url https://api.trycactus.com/v1/underwriting-inputs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"document_ids": [
"<string>"
],
"investment_strategy": "mf-value-add",
"sourced_only": false,
"end_user_ref": "<string>"
}
'import requests
url = "https://api.trycactus.com/v1/underwriting-inputs"
payload = {
"document_ids": ["<string>"],
"investment_strategy": "mf-value-add",
"sourced_only": False,
"end_user_ref": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
document_ids: ['<string>'],
investment_strategy: 'mf-value-add',
sourced_only: false,
end_user_ref: '<string>'
})
};
fetch('https://api.trycactus.com/v1/underwriting-inputs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.trycactus.com/v1/underwriting-inputs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'document_ids' => [
'<string>'
],
'investment_strategy' => 'mf-value-add',
'sourced_only' => false,
'end_user_ref' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.trycactus.com/v1/underwriting-inputs"
payload := strings.NewReader("{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.trycactus.com/v1/underwriting-inputs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycactus.com/v1/underwriting-inputs")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "uwi_01J9ZK4P",
"object": "underwriting_inputs",
"status": "processing",
"sandbox": true,
"created_at": "2023-11-07T05:31:56Z",
"progress": {
"phase": "ingesting",
"detail": "<string>"
},
"document_ids": [
"<string>"
],
"asset_class": "multifamily",
"investment_strategy": "<string>",
"schema_version": "underwriting_inputs.v1",
"billed": {
"rate_code": "<string>",
"units": 123,
"amount_usd": "<string>"
},
"billed_total_usd": "<string>",
"completed_at": "2023-11-07T05:31:56Z",
"elapsed_seconds": 123,
"poll_after_seconds": 123,
"result_url": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
}Extract normalized underwriting model inputs from documents
Reads every supplied document together and returns the populated input fields of the underwriting model for an asset class and investment strategy — a stable, documented field set, whatever shape the source documents took.
This differs from POST /v1/extractions in kind, not quality.
An extraction reports what one document says, in that document’s
own structure, with cell-level provenance. This reports the model’s
fields, reconciled across documents. Use extractions for rent rolls
and T-12s, where the document is the structure; use this when you
need a guaranteed field set — offering memoranda especially, whose
layout varies per document.
Every field carries the basis on which it was populated.
document and derived values came from your documents and cite
them; assumed values are model defaults chosen where the
documents were silent, and carry no citation. validation.coverage
reports the split. Pass sourced_only to receive only what the
documents supported.
curl --request POST \
--url https://api.trycactus.com/v1/underwriting-inputs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"document_ids": [
"<string>"
],
"investment_strategy": "mf-value-add",
"sourced_only": false,
"end_user_ref": "<string>"
}
'import requests
url = "https://api.trycactus.com/v1/underwriting-inputs"
payload = {
"document_ids": ["<string>"],
"investment_strategy": "mf-value-add",
"sourced_only": False,
"end_user_ref": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
document_ids: ['<string>'],
investment_strategy: 'mf-value-add',
sourced_only: false,
end_user_ref: '<string>'
})
};
fetch('https://api.trycactus.com/v1/underwriting-inputs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.trycactus.com/v1/underwriting-inputs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'document_ids' => [
'<string>'
],
'investment_strategy' => 'mf-value-add',
'sourced_only' => false,
'end_user_ref' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.trycactus.com/v1/underwriting-inputs"
payload := strings.NewReader("{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.trycactus.com/v1/underwriting-inputs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycactus.com/v1/underwriting-inputs")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"document_ids\": [\n \"<string>\"\n ],\n \"investment_strategy\": \"mf-value-add\",\n \"sourced_only\": false,\n \"end_user_ref\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "uwi_01J9ZK4P",
"object": "underwriting_inputs",
"status": "processing",
"sandbox": true,
"created_at": "2023-11-07T05:31:56Z",
"progress": {
"phase": "ingesting",
"detail": "<string>"
},
"document_ids": [
"<string>"
],
"asset_class": "multifamily",
"investment_strategy": "<string>",
"schema_version": "underwriting_inputs.v1",
"billed": {
"rate_code": "<string>",
"units": 123,
"amount_usd": "<string>"
},
"billed_total_usd": "<string>",
"completed_at": "2023-11-07T05:31:56Z",
"elapsed_seconds": 123,
"poll_after_seconds": 123,
"result_url": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
}Authorizations
Partner API key issued by Cactus.
Headers
Unique key making the request safely retryable.
255Body
Documents to read together. They are reconciled as one property, so send the whole package (OM, rent roll, T-12) rather than one job per file — a field stated in one document is available to every section.
1 - 10 elementsSelects the underwriting model. Only asset classes with a
model behind them are accepted; the rest return 422
(unsupported_asset_class).
multifamily, self-storage, industrial-outdoor-storage, commercial, industrial, office, retail, hotel Strategy within the asset class. Defaults to that class's value-add strategy.
"mf-value-add"
Return only fields the documents supported (basis of
document or derived), omitting model defaults.
validation.coverage still counts the full run, so you can see
how much was withheld.
Your own identifier for the end user this job is for. Isolates the job's working data from other end users'.
1 - 255Response
Job accepted.
"uwi_01J9ZK4P"
"underwriting_inputs"processing, completed, failed Present while the job is active.
Show child attributes
Show child attributes
multifamily, self-storage, industrial-outdoor-storage, commercial, industrial, office, retail, hotel "underwriting_inputs.v1"Show child attributes
Show child attributes
Whole seconds since created_at. Present while the job is active.
Recommended seconds to wait before polling again. Mirrors the Retry-After header.
Present when completed.
Show child attributes
Show child attributes