The ForVue Partner API gives your platform programmatic access to predictive AND operational maintenance intelligence for multifamily and commercial real estate. Integrate once, and your users can see risk scores, projected failures, reserve recommendations, insurance RCV, lender-grade condition scores, diagnostic suggestions, vendor matches, and parts-availability data — derived from a proprietary multi-factor Weibull-Bayesian scoring engine with a cascade dependency model, layered with a 30-type / 169-component knowledge base calibrated against ASHRAE, HUD, and NAHB published standards. The specific factors, weights, cascade rules, and formulas are trade secrets of Wise Capital, LLC (DTSA-protected; USPTO 64/032,704).
https://platform.investwisecap.com/api/v1
All endpoints in this reference are relative to this base. Example: /v1/properties is reached at https://platform.investwisecap.com/api/v1/properties.
The fastest way to verify credentials and connectivity:
# Replace fv_live_XXX with your issued API key
curl -i https://platform.investwisecap.com/api/v1/ping \
-H "X-Api-Key: fv_live_XXX"
Successful response:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: "2026-04-21T00:00:00.000Z"
Content-Type: application/json
{
"ok": true,
"timestamp": "2026-04-20T14:30:00.000Z",
"partner": "AppFolio"
}
If you see HTTP 401, your key is invalid. If you see HTTP 429, you've exceeded your daily rate limit (reset at midnight UTC). See Section 11 for a full error reference.
?sandbox=true to any list endpoint. No real operator data is returned. See Section 6.
| Step | What to Build | Reference |
|---|---|---|
| 1 | Store API credentials securely (env vars, secret manager). Never commit to source control. | § 2 |
| 2 | Wrap outbound calls with rate-limit awareness using the three response headers. | § 3 |
| 3 | Implement pagination for list endpoints. Never assume all data fits in one response. | § 4 |
| 4 | Generate unique Idempotency-Key headers for every POST that creates data. | § 5 |
| 5 | Set up a webhook receiver with HMAC signature verification. | § 9 |
| 6 | Handle all 4xx and 5xx error codes gracefully — never silent-fail on partner data. | § 11 |
ForVue supports two authentication methods. You may use either for any endpoint that requires authentication. Both produce the same access scope — your choice comes down to operational preference.
| Method | Best For | Expiry | Revocation |
|---|---|---|---|
| API KEY | Simple server-to-server scripts, scheduled jobs, prototypes. | Never (until rotated) | By Wise Capital admin |
| OAUTH 2.0 | Production integrations, user-initiated flows, multi-tenant apps. | 1 hour | By expiry or admin |
Pass your API key in the X-Api-Key request header on every call:
curl https://platform.investwisecap.com/api/v1/properties \
-H "X-Api-Key: fv_live_7f8a9b2c3d4e5f6a7b8c9d0e1f2a3b4c"
API keys are prefixed fv_live_ followed by 48 hexadecimal characters. They never expire but can be rotated at any time by a Wise Capital administrator. When a key is rotated, the previous key is immediately invalidated.
OAuth is the preferred method for production partners. You exchange a client_id and client_secret for a short-lived bearer token, then use that token on subsequent API calls.
curl -X POST https://platform.investwisecap.com/api/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "your_client_id",
"client_secret": "your_client_secret"
}'
Response:
{
"access_token": "fvt_abc123def456...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write",
"partner": "AppFolio"
}
curl https://platform.investwisecap.com/api/v1/properties \
-H "Authorization: Bearer fvt_abc123def456..."
fvt_ prefix + 64 hexadecimal charactersGET /oauth/token/info returns active/expiry status for a tokenThree endpoints do not require authentication:
GET /v1/openapi.json — OpenAPI 3.0 specificationGET /v1/auth/methods — lists available authentication methodsPOST /oauth/token — token exchange (authenticates via client credentials)ForVue enforces three independent rate limits. The first is per-partner and per-day (your daily budget). The other two are transport-layer safeguards that apply to every request regardless of authentication, to protect Platform availability.
Every partner is assigned a daily call budget enforced in a rolling 24-hour window from midnight UTC to midnight UTC. The default is 1,000 calls per day. Higher limits are available by agreement.
Every authenticated response includes three rate-limit headers:
| Header | Type | Meaning |
|---|---|---|
X-RateLimit-Limit | integer | Your daily maximum. Example: 1000. |
X-RateLimit-Remaining | integer | Calls remaining in the current window. Example: 847. |
X-RateLimit-Reset | string (ISO 8601) | UTC timestamp when the counter resets. Always the next midnight UTC. |
In addition to the per-partner daily budget, all requests to the Platform are subject to two safeguards enforced at the transport layer:
| Scope | Limit | Response when exceeded |
|---|---|---|
| Per source IP address | 120 requests / minute | HTTP 429, body: {"error":"Too many requests. Please slow down."} |
| Per authenticated user or partner | 60 requests / minute | HTTP 429, body: {"error":"Rate limit exceeded. Maximum 60 requests per minute."} |
Requests that trip either transport-layer limit do not count against your daily budget. Both limits are subject to change without notice; they exist to protect Platform availability and are not intended as a substitute for a properly sized commercial rate limit.
When the remaining daily count hits zero, subsequent calls return HTTP 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: "2026-07-10T00:00:00.000Z"
Content-Type: application/json
{
"error": "Daily rate limit exceeded (1000 calls/day). Resets at midnight UTC."
}
Best practices:
X-RateLimit-Remaining on every response. When it drops below 10% of your limit, alert your operations team.429 responses. Wait at least until X-RateLimit-Reset before retrying.POST /v1/appliances/bulk (one call) instead of many individual POST /v1/appliances calls.All list endpoints support offset-based pagination. This is critical for partners with large portfolios — a single property may have hundreds of components, and a portfolio may have thousands of properties.
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 50 | 200 | Records per page. Values above 200 are capped. |
offset | integer | 0 | — | Records to skip. Use to fetch subsequent pages. |
Every paginated endpoint returns the collection plus pagination metadata:
{
"properties": [ // or "components", "alerts", "events", etc.
{ ... 50 records ... }
],
"total": 342,
"limit": 50,
"offset": 0,
"page": 1,
"pages": 7,
"partner": "AppFolio"
}
Example — fetch every property using pagination:
// Pseudocode
let offset = 0;
const limit = 200;
const all = [];
while (true) {
const res = await fetch(
`${BASE}/v1/properties?limit=${limit}&offset=${offset}`,
{ headers: { 'X-Api-Key': API_KEY } }
).then(r => r.json());
all.push(...res.properties);
if (offset + limit >= res.total) break;
offset += limit;
}
The following endpoints support limit and offset:
GET /v1/propertiesGET /v1/componentsGET /v1/alertsGET /v1/portfolio/summaryGET /v1/eventsGET /v1/property/{id}/claimsGET /v1/components/{id}/trendoffset exceeds total, you receive an empty collection array plus correct total and pages values. No error.
Write endpoints that create resources support idempotency keys to prevent duplicate records when a request must be retried (e.g., after a timeout or network error).
Send a unique string in the Idempotency-Key request header when creating data:
curl -X POST https://platform.investwisecap.com/api/v1/appliances \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: appfolio-sync-2026-04-20-unit-3b-hvac" \
-d '{ "property_id": "P_abc123", "type_id": "hvac_central", ... }'
HTTP 200. The request body is NOT re-processed.| Endpoint | Why It Matters |
|---|---|
POST /v1/properties | Avoid duplicate property records during PMS sync. |
POST /v1/appliances | Avoid duplicate appliance entries. |
POST /v1/appliances/bulk | Batch-safe; never re-process a batch. |
POST /v1/meter-event | Prevent double-booking sensor events. |
POST /v1/meter-event/smart | Same; includes auto-creation of properties/appliances. |
POST /v1/meter-event/smart/v2 | Includes webhook side-effects; idempotency critical. |
POST /v1/service-events/bulk | Bulk service event imports. |
POST /v1/property/{id}/claims | Prevent duplicate insurance claim imports. |
{partner}-{resource_type}-{external_id}-{operation}.-_:..abc123 does not collide with another partner's abc123.Sandbox mode lets partner engineers develop and test against realistic demo data without touching any real operator's portfolio. Credentials are the same — only the data is different.
Append ?sandbox=true to any supported list endpoint:
curl "https://platform.investwisecap.com/api/v1/properties?sandbox=true" \
-H "X-Api-Key: fv_live_XXX"
Only records belonging to demo properties (created via the ForVue Welcome Wizard or POST /onboarding/demo-property) are returned.
GET /v1/propertiesGET /v1/componentsGET /v1/alertsGET /v1/portfolio/summaryGET /v1/eventsSandbox is a read-only filter. It does not apply to write endpoints — POST /v1/appliances with ?sandbox=true still writes to the live data store (scoped to the target property).
A demo property typically contains:
The ForVue platform organizes real estate intelligence into a clear four-level hierarchy. Understanding this hierarchy is essential for integration — most endpoints accept a property, appliance, or component ID as a path parameter.
Property (a physical address with rental units)
│
├─ Unit (individual rentable unit, e.g., "Unit 3B")
│
└─ Appliance (major equipment at the property, optionally in a unit)
│
└─ Component (individual scoreable part of an appliance)
│
├─ Service Event (maintenance record)
└─ Risk Snapshot (daily score history)
A single physical property. Operators may own many properties; each property has an owner and optionally a partner reference (partner_property_id) for cross-system identification.
| Field | Type | Description |
|---|---|---|
id | string | Prefixed unique ID, e.g., P_abc123 |
name | string | Display name (e.g., "Maple Ridge Apartments") |
address, city, state, zip | string | Physical address |
unit_count | integer | Total rentable units (billing basis) |
year_built | integer | Year constructed (optional, improves scoring) |
estimated_value | number | Optional — enables deferred_as_pct_of_value in RCV endpoint |
is_demo | boolean | true for demo properties; excluded from billing |
created_at | string (ISO 8601) | Creation timestamp |
A major piece of equipment installed at a property (HVAC unit, water heater, boiler, elevator, etc.). Optionally tied to a specific unit.
| Field | Type | Description |
|---|---|---|
id | string | Prefixed unique ID, e.g., A_xyz789 |
property_id | string | Parent property |
unit_id | string? | Parent unit (optional — some appliances are property-wide) |
type_id | string | Appliance type from the Knowledge Base (see Appendix) |
brand, model, serial | string | Manufacturer identification |
brand_tier | string | premium · standard · budget — affects scoring |
install_year | integer | Year installed — primary age input to scoring |
usage_intensity | number | 0.5 (light) to 2.0 (heavy); default 1.0 |
warranty_expiry | string (date) | Warranty end date |
A single scoreable part of an appliance (e.g., a water heater's anode rod, tank, or pressure relief valve). Each appliance has a deterministic set of components based on its type — created automatically when the appliance is created.
| Field | Type | Description |
|---|---|---|
id | string | Prefixed unique ID, e.g., C_def456 |
appliance_id | string | Parent appliance |
component_def_id | string | Reference to Knowledge Base definition (e.g., wh_gas_anode) |
install_year | integer | Defaults to parent appliance install year unless separately replaced |
last_replaced | string (date) | Most recent replacement; resets the age clock |
last_serviced | string (date) | Most recent inspection or maintenance |
override_lifespan | integer? | Override default Weibull lifespan (rare) |
A maintenance record: preventive maintenance, inspection, repair, replacement, emergency repair, etc. Events feed back into the scoring engine as Bayesian evidence.
| Field | Type | Description |
|---|---|---|
id | string | Prefixed unique ID, e.g., SE_abc123 |
appliance_id | string | Subject of the event |
component_id | string? | Specific component (optional — may apply to whole appliance) |
event_type | string | One of 9 event types (see below) |
date | string (date) | Event date (YYYY-MM-DD) |
parts_cost, labor_cost, total_cost | number | Cost breakdown in USD |
notes | string | Free-form description; scanned for risk keywords |
condition_after | string | good · fair · poor (optional) |
Valid event_type values:
| Type | Effect on Scoring |
|---|---|
Preventive Maintenance | Positive — may lower risk if completed on at-risk components |
Inspection | Neutral to positive — updates confidence, provides data |
Filter Change | Positive — HVAC/water specific |
Cleaning | Positive — component specific |
Repair | Neutral — recent repairs add risk (repair frequency factor) |
Replacement | Resets age clock; captures Validation Data for accuracy tracking |
Emergency Repair | Captures Validation Data; high-weight signal of failure |
Warranty Claim | Neutral — informational |
Other | Neutral — informational |
An immutable daily record of a component's risk score, taken at 3:00 AM UTC. Enables time-series trending via GET /v1/components/{id}/trend. Retained for 365 days.
All resource IDs are prefixed strings, never sequential integers. Prefixes encode the resource type for debuggability:
| Prefix | Resource | Example |
|---|---|---|
P_ | Property | P_abc123 |
U_ | Unit | U_xyz789 |
A_ | Appliance | A_def456 |
C_ | Component | C_ghi789 |
SE_ | Service Event | SE_jkl012 |
CLM_ | Insurance Claim | CLM_mno345 |
This section explains how ForVue produces risk scores so your engineers can explain the output to your users without needing to contact us. The underlying math, specific parameter values, brand multiplier tables, likelihood ratios, and cascade rules are proprietary trade secrets protected under the DTSA and are not disclosed in this document.
Every component receives a risk score — a number between 0.00 and 0.99 representing the estimated cumulative probability of failure within the component's remaining predicted lifespan.
The scoring engine is a proprietary multi-factor composite Weibull-Bayesian model layered with a cascade dependency mechanism, calibrated against ASHRAE Applications Ch.38, HUD, NAHB, and RSMeans published data. Inputs include calendar age, Bayesian updates from logged service events, environmental and usage adjustments, manufacturer characteristics, and cross-component dependencies — combined under a proprietary weighting model.
The specific factors, weights, thresholds, cascade rules, and formulas are trade secrets of Wise Capital, LLC and are not published — protected under DTSA, with the broader scoring methodology covered by USPTO Provisional Patent Application 64/032,704. Scores themselves are deterministic and independently verifiable from your service-event history; the engine internals are not.
Every risk score is also classified into one of three tiers — a simplification partners can display in user interfaces without exposing the raw score:
| Tier | Score Range | Meaning |
|---|---|---|
CRITICAL | >= 0.78 | High probability of failure within 12 months. Immediate proactive action recommended to avoid reactive costs that are typically 3–12× higher than proactive intervention. |
WARNING | 0.52 – 0.77 | Elevated risk. Schedule preventive maintenance within 6 months. |
GOOD | < 0.52 | Standard monitoring. Follow routine maintenance schedules. |
Every risk score ships with a confidence rating reflecting how much data the engine had to work with:
| Confidence | Margin of Error | Projected Range Width | Typical Cause |
|---|---|---|---|
HIGH | ± 2% | ±4% of effective lifespan | Multiple service events, observed conditions, known brand/year |
MEDIUM | ± 3% | ±8% of effective lifespan | Some service history or known brand |
LOW | ± 4% | ±12% of effective lifespan | Sparse data; newly added appliance with no service events |
The _score_data object returned with components includes projected_failure_range:
"projected_failure_range": {
"earliest": 2027,
"latest": 2029,
"confidence_pct": 92
}
Risk scores are recomputed:
POST /v1/meter-event/smart and variantsPartner integrations polling more frequently than daily add no value. Use the event stream (Section 10) or webhooks (Section 9) for change notifications instead.
Webhooks deliver real-time events from ForVue to your system as they happen. Configure a webhook URL during partner onboarding and your endpoint will receive signed HTTP POST requests whenever a component crosses a risk threshold, a service event is logged, or a sensor event is processed.
Every webhook delivery is a POST request with this envelope:
POST https://your-server.com/forvue-webhook HTTP/1.1
Content-Type: application/json
User-Agent: ForVue-Webhook/1.0
X-ForVue-Signature: sha256=9a8f7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a...
X-ForVue-Delivery: WH_1713620400000_AB7X9
X-ForVue-Event: component.critical
{
"event": "component.critical",
"timestamp": "2026-04-20T14:30:00.000Z",
"partner_id": "PARTNER_abc123",
"partner": "AppFolio",
"version": "v1",
"data": { // event-specific payload — see Section 9.3 }
}
Every delivery includes an HMAC-SHA256 signature computed from your partner's webhook_secret and the raw request body. Your webhook endpoint must verify this signature before processing any event — otherwise, any attacker who discovers your URL can send forged events.
Header name: X-ForVue-Signature
Value format: sha256=<hex-encoded HMAC-SHA256 digest>
const crypto = require('crypto');
function verifyForVueSignature(rawBody, signatureHeader, webhookSecret) {
if (!signatureHeader || !signatureHeader.startsWith('sha256=')) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex');
// timingSafeEqual prevents timing attacks
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader);
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}
// Express example
app.post('/forvue-webhook',
express.raw({ type: 'application/json' }), // raw body required
(req, res) => {
const rawBody = req.body.toString('utf8');
const valid = verifyForVueSignature(
rawBody,
req.headers['x-forvue-signature'],
process.env.FORVUE_WEBHOOK_SECRET
);
if (!valid) return res.status(401).json({ error: 'Invalid signature' });
const event = JSON.parse(rawBody);
// ... process event ...
res.status(200).json({ received: true });
}
);
# Verify manually against a captured webhook body
BODY=$(cat webhook-body.json)
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$FORVUE_WEBHOOK_SECRET" -binary | xxd -p -c 256)"
[ "$SIG" = "$RECEIVED_SIGNATURE" ] && echo "valid" || echo "invalid"
Use whichever HMAC-SHA256 primitive your stack ships. The Node example above is our canonical reference; language-native constant-time-equal / timingSafeEqual comparators must be used to prevent timing side-channels.
Nine event types are currently emitted. Your endpoint should implement a case statement on the event field and gracefully ignore unknown event types (ForVue may add new events without a breaking version bump).
A component crossed the CRITICAL threshold (score ≥ 0.78). Triggered by the 3 AM daily snapshot or immediately after a smart meter event.
{
"event": "component.critical",
"timestamp": "2026-04-20T03:00:00.000Z",
"partner_id": "PARTNER_abc123",
"partner": "AppFolio",
"version": "v1",
"data": {
"component_id": "C_def456",
"component_name": "Anode Rod",
"component_def_id": "wh_gas_anode",
"appliance_id": "A_ghi789",
"appliance_type": "water_heater_gas",
"property_id": "P_abc123",
"property_name": "Maple Ridge Apartments",
"risk_score": 0.847,
"risk_tier": "CRITICAL",
"previous_tier": "WARNING",
"confidence": "HIGH",
"proactive_cost": 220,
"reactive_cost": 1800
}
}
A component crossed the WARNING threshold (0.52 ≤ score < 0.78). Same payload shape as component.critical with risk_tier set to WARNING.
A component returned to GOOD from CRITICAL or WARNING — typically after a Replacement service event. Same payload; risk_tier is GOOD and previous_tier is the prior elevated tier.
A service event (repair, inspection, preventive maintenance, etc.) was logged for an appliance.
{
"event": "service_event.created",
"timestamp": "2026-04-20T14:30:00.000Z",
"data": {
"event_id": "SE_xyz789",
"event_type": "Repair",
"appliance_id": "A_ghi789",
"appliance_type": "water_heater_gas",
"property_id": "P_abc123",
"property_name": "Maple Ridge Apartments",
"total_cost": 265,
"date": "2026-04-20"
}
}
A new property was created. Fires for all creation paths including partner API writes and auto-creation from smart meter events.
{
"event": "property.created",
"data": {
"property_id": "P_abc123",
"address": "123 Main St",
"city": "Louisville",
"state": "KY",
"source": "sensor_event"
}
}
A new appliance was added to a property.
{
"event": "appliance.created",
"data": {
"appliance_id": "A_ghi789",
"type_id": "hvac_central",
"property_id": "P_abc123"
}
}
A raw sensor event was processed via POST /v1/meter-event. Fired for basic (non-smart) meter events.
A smart sensor event was processed via POST /v1/meter-event/smart/v2, including auto-creation of missing property/appliance records and re-scoring of affected components.
{
"event": "sensor.smart",
"data": {
"event_id": "PE_klm456",
"event_type": "Replacement",
"property_id": "P_abc123",
"appliance_id": "A_ghi789",
"risk_summary": {
"components_scored": 6,
"critical_count": 1,
"warning_count": 2
}
}
}
Legacy callback envelope used by the v1 smart meter callback flow. New integrations should use sensor.smart instead.
Emitted when an admin triggers a manual test from the ForVue dashboard. Useful for verifying your endpoint is reachable and your signature verification is working.
2xx (preferably 200) within 8 seconds to acknowledge receipt.X-ForVue-Delivery as a dedupe key.200 immediately and queue the event for background work.If your endpoint fails to respond 2xx within 8 seconds, ForVue retries with exponential backoff:
| Attempt | Delay | Cumulative |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | +5 seconds | 5s |
| 3 | +30 seconds | 35s |
After 3 failed attempts, the delivery is marked as failed but logged in the ForVue delivery log. Admins can manually resend failed deliveries via POST /admin/webhook-deliveries/{id}/resend.
Every webhook attempt — successful or failed — is recorded with:
X-ForVue-Delivery header)Partners can request delivery log exports by emailing wise@investwisecap.com.
Webhook URL, secret rotation, and event type filters are configured per-partner by a Wise Capital administrator. Email wise@investwisecap.com with:
If webhooks aren't practical for your architecture (firewall constraints, no public endpoint, preference for pull over push), the event stream endpoint provides a polling-based alternative. Query it periodically to get every change since your last sync.
GET /v1/events?since=2026-04-15T00:00:00Z&limit=100&offset=0
| Param | Type | Required | Description |
|---|---|---|---|
since | string (ISO 8601) | Required | Returns events after this timestamp. Example: 2026-04-15T00:00:00Z |
limit | integer | Optional | Records per page. Default: 50. Max: 200. |
offset | integer | Optional | Records to skip. Default: 0. |
| Event Type | Source | When Returned |
|---|---|---|
property.created | Properties collection | Property created_at > since |
appliance.created | Appliances collection | Appliance created_at > since |
service_event.created | Service events collection | Event created_at > since |
component.critical | Components (live scoring) | Always included if currently CRITICAL |
component.warning | Components (live scoring) | Always included if currently WARNING |
component.critical and component.warning events are included regardless of the since timestamp. They represent the current state of at-risk components, not a historical change. This means the event stream doubles as an "active alerts" query.
{
"events": [
{
"type": "service_event.created",
"timestamp": "2026-04-20T14:30:00.000Z",
"data": {
"id": "SE_xyz789",
"event_type": "Repair",
"appliance_id": "A_ghi789",
"total_cost": 265,
"date": "2026-04-20"
}
},
{
"type": "component.critical",
"timestamp": "2026-04-20T18:00:00.000Z",
"data": {
"id": "C_def456",
"component_name": "wh_gas_anode",
"risk_score": 0.832,
"risk_tier": "CRITICAL",
"property_id": "P_abc123"
}
}
],
"total": 42,
"limit": 100,
"offset": 0,
"page": 1,
"pages": 1,
"since": "2026-04-15T00:00:00Z",
"partner": "AppFolio"
}
since= set to 30 days ago (or your desired lookback)timestamp from the responsesince= set to your last stored timestampevents array is empty or offset + limit >= totaltype, deduplicate by data.idRecommended polling interval: every 15 minutes for near-real-time, hourly for daily-sync use cases. Risk scores only update at 3 AM UTC, so more frequent polling adds no scoring value.
All errors return a JSON body with an error field. Partners should handle errors by HTTP status code and use the error string for logging and debugging — not for conditional logic (error strings may change without notice).
| Status | Meaning | Example error | Action |
|---|---|---|---|
400 | Bad Request — missing or invalid parameters | "name, address, state required" | Fix request body/params. Check required fields. |
401 | Unauthorized — invalid or missing credentials | "API key required. Pass via X-Api-Key header." | Check API key or refresh OAuth token. |
401 | OAuth token expired | "Invalid or expired OAuth token. Re-authenticate at POST /oauth/token" | Request a new token. |
404 | Not Found — resource doesn't exist | "Property not found" | Verify the ID. Resource may have been deleted. |
409 | Conflict — resource already exists | "Demo property already exists" | Use the existing resource or delete first. |
429 | Rate Limited — daily call budget exceeded | "Daily rate limit exceeded (1000 calls/day). Resets at midnight UTC." | Wait until X-RateLimit-Reset. See § 3. |
500 | Internal Server Error | "Internal server error" | Retry with backoff. If persistent, contact support. |
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "property_id, type_id, install_year required"
}
Bulk write endpoints (/v1/appliances/bulk, /v1/service-events/bulk, /v1/property/{id}/claims) return partial success. Some records may succeed while others fail:
HTTP/1.1 201 Created
{
"created": 8,
"errors": 2,
"events": [ /* 8 successfully created records */ ],
"error_details": [
{ "index": 3, "error": "Appliance not found: A_invalid_id" },
{ "index": 7, "error": "event_type and date required" }
]
}
Always check both created and errors. If errors > 0, inspect error_details for per-record failure reasons and retry or fix those records.
| Status | Retryable? | Strategy |
|---|---|---|
400 | No | Fix request and resend. |
401 | Yes (after re-auth) | If API key: contact Wise Capital. If OAuth: request new token. |
404 | No | Resource deleted or never existed. |
429 | Yes (after wait) | Wait until X-RateLimit-Reset timestamp. |
500 | Yes | Exponential backoff: 1s, 2s, 4s, 8s, max 60s. Max 5 retries. |
502/503/504 | Yes | Same backoff. ForVue may be restarting (typically < 5 seconds). |
This section documents every read endpoint in the Partner API. Each entry includes method, path, authentication, parameters, response schema, a working curl example, and error cases specific to that endpoint.
Health check. Returns a 200 if your credentials are valid and ForVue is operational. Use this endpoint as a connectivity test during integration and as an ongoing heartbeat check.
curl https://platform.investwisecap.com/api/v1/ping \
-H "X-Api-Key: fv_live_XXX"
{
"ok": true,
"timestamp": "2026-04-20T14:30:00.000Z",
"partner": "AppFolio"
}
| Field | Type | Description |
|---|---|---|
ok | boolean | Always true on success |
timestamp | string (ISO 8601) | Server time at request |
partner | string | Your partner company name |
401 — Missing or invalid credentials429 — Rate limit exceededOpenAPI 3.0 specification. Returns the full machine-readable API spec. Load this into Postman, Insomnia, Stoplight, or any OpenAPI-compatible tooling to auto-generate client SDKs and test harnesses.
curl https://platform.investwisecap.com/api/v1/openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "ForVue Partner API",
"version": "1.0.0",
"description": "Predictive maintenance intelligence..."
},
"servers": [ { "url": "/v1" } ],
"security": [ { "apiKey": [] }, { "oauth2": [] } ],
"paths": { /* all 33 endpoints described */ }
}
openapi.json, the JSON wins. Programmatic integrations should always consume the live spec.
Authentication method discovery. Returns a list of supported authentication methods and their configuration details. Useful for SDKs that want to auto-detect whether a given partner should use API keys or OAuth.
curl https://platform.investwisecap.com/api/v1/auth/methods
{
"methods": [
{
"type": "api_key",
"header": "X-Api-Key",
"description": "Static API key — simple, no expiry"
},
{
"type": "oauth2",
"grant": "client_credentials",
"token_endpoint": "/oauth/token",
"description": "Bearer token — expires in 1 hour, preferred for production"
}
],
"docs": "Contact wise@investwisecap.com for credentials"
}
List all properties. Returns a paginated list of properties accessible to your partner scope. Use this as the entry point for any integration that needs to enumerate a customer's portfolio.
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Records per page (max 200) |
offset | integer | 0 | Records to skip |
sandbox | string | — | Pass true to return only demo properties |
curl "https://platform.investwisecap.com/api/v1/properties?limit=50" \
-H "X-Api-Key: fv_live_XXX"
{
"properties": [
{
"id": "P_abc123",
"name": "Maple Ridge Apartments",
"address": "123 Main St",
"city": "Louisville",
"state": "KY",
"zip": "40202",
"unit_count": 24,
"created_at": "2026-03-15T10:00:00.000Z"
}
],
"total": 142,
"limit": 50,
"offset": 0,
"page": 1,
"pages": 3,
"partner": "AppFolio"
}
401 — Missing or invalid credentials429 — Rate limit exceededPortfolio-wide rollup. Returns every property with a risk summary, financial rollup, and appliance/component counts in a single call. Designed for dashboard displays where you need the portfolio overview without per-property round trips.
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Records per page |
offset | integer | 0 | Records to skip |
sandbox | string | — | true for demo properties only |
curl https://platform.investwisecap.com/api/v1/portfolio/summary \
-H "X-Api-Key: fv_live_XXX"
{
"portfolio": [
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"address": "123 Main St",
"city": "Louisville",
"state": "KY",
"unit_count": 24,
"appliances": 8,
"components": 52,
"critical": 3,
"warning": 7,
"good": 42,
"overall_rating": "POOR",
"total_deferred_maintenance": 14500,
"total_reactive_exposure": 89200,
"deferred_per_door": 604
}
],
"total": 142,
"limit": 50,
"offset": 0,
"totals": {
"properties": 142,
"appliances": 1138,
"components": 7402,
"critical": 47,
"warning": 184,
"good": 7171,
"total_deferred": 1840000,
"total_reactive": 12650000
},
"partner": "AppFolio"
}
/v1/properties and then calling /v1/property/{id}/summary for each.
401 — Missing or invalid credentials429 — Rate limit exceededProperty-level summary. Returns risk tier breakdown, financial totals, deferred maintenance, reactive exposure, and recommended monthly reserve for a single property. Use this for a property detail page.
| Param | Type | Description |
|---|---|---|
id | string | Property ID (e.g., P_abc123) |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/summary \
-H "X-Api-Key: fv_live_XXX"
{
"property": {
"id": "P_abc123",
"name": "Maple Ridge Apartments",
"address": "123 Main St",
"city": "Louisville",
"state": "KY",
"unit_count": 24
},
"counts": {
"appliances": 8,
"components": 52,
"service_events": 14
},
"risk": {
"critical": 3,
"warning": 7,
"good": 42,
"overall_rating": "POOR"
},
"financials": {
"total_deferred_maintenance": 14500,
"total_reactive_exposure": 89200,
"deferred_per_door": 604,
"recommended_monthly_reserve_per_unit": 25
},
"assessed_at": "2026-04-20T14:30:00.000Z",
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Property not found or not accessible429 — Rate limit exceededComprehensive property report. Returns the full scoring breakdown: property info, per-appliance analysis with components grouped by risk tier, system category rollups, and financial projections. This is the data backing a Bank Origination or CNA report.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/report \
-H "X-Api-Key: fv_live_XXX"
{
"property": { /* full property record */ },
"overall": {
"rating": "POOR",
"nci_equivalent": 72,
"components_assessed": 52
},
"categories": {
"water_heater_gas": { "critical": 1, "warning": 2, "good": 3, "deferred": 2200 },
"hvac_central": { "critical": 1, "warning": 3, "good": 8, "deferred": 5800 }
},
"critical": [
{
"component_id": "C_def456",
"component_name": "Anode Rod",
"appliance_type": "water_heater_gas",
"risk_score": 0.847,
"confidence": "HIGH",
"age_years": 12,
"projected_failure_year": 2026,
"proactive_cost": 220,
"reactive_cost": 1800
}
],
"warning": [ /* array of WARNING components */ ],
"good": [ /* array of GOOD components */ ],
"financials": {
"total_deferred": 14500,
"total_reactive_exposure": 89200,
"deferred_per_door": 604,
"estimated_savings_if_acted": 74700,
"recommended_monthly_reserve_per_unit": 25
},
"assessed_at": "2026-04-20T14:30:00.000Z",
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceeded30/60/90-day failure forecast. Returns components grouped into three time windows based on predicted failure likelihood. Designed for scheduling preventive maintenance crews and budgeting short-term capex.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/forecast \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"forecast": {
"window_30_days": {
"label": "Immediate — Act Within 30 Days",
"component_count": 3,
"proactive_cost": 850,
"emergency_cost_if_ignored": 7200,
"savings_potential": 6350,
"components": [ /* ... */ ]
},
"window_60_days": {
"label": "Near-Term — Schedule Within 60 Days",
"component_count": 5,
"proactive_cost": 1400,
"emergency_cost_if_ignored": 9800,
"savings_potential": 8400,
"components": [ /* ... */ ]
},
"window_90_days": {
"label": "Short-Term — Plan Within 90 Days",
"component_count": 6,
"proactive_cost": 2100,
"emergency_cost_if_ignored": 12300,
"savings_potential": 10200,
"components": [ /* ... */ ]
}
},
"generated_at": "2026-04-20T14:30:00.000Z",
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededReserve fund recommendations. Returns four scheduling options (12-month, 24-month, 36-month, 10-year) for capital reserves. Designed for bank underwriting and HUD CNA filings — gives lenders and auditors a range of reserve strategies, each with monthly and annual figures per unit and property-wide.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/reserve \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"unit_count": 24,
"total_deferred": 14500,
"reserves": {
"12_month": {
"label": "Aggressive — Address All Deferred Within 1 Year",
"per_unit_per_month": 50,
"per_unit_per_year": 600,
"property_per_month": 1200
},
"24_month": {
"label": "Standard — Address All Deferred Within 2 Years",
"per_unit_per_month": 25,
"per_unit_per_year": 300,
"property_per_month": 600
},
"36_month": {
"label": "Conservative — Address All Deferred Within 3 Years",
"per_unit_per_month": 17,
"per_unit_per_year": 204,
"property_per_month": 408
},
"10_year_full_replacement": {
"label": "Long-Term — Full Replacement Fund Over 10 Years",
"per_unit_per_month": 310,
"per_unit_per_year": 3720,
"property_per_month": 7440
}
},
"generated_at": "2026-04-20T14:30:00.000Z",
"partner": "AppFolue"
}
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededSingle lender-friendly condition score. Returns a 1-100 numeric score with an A-F letter grade and an NSPIRE-style rating (GOOD / FAIR / FAIL — HUD's standardized inspection scale that replaced UPCS in 2023). Banks use this field directly in their underwriting workflow. One number, one grade — no interpretation required.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/condition-score \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"condition_score": 72,
"grade": "C",
"rating": "FAIL",
"components_assessed": 52,
"critical": 3,
"warning": 7,
"methodology": "ForVue Weibull-Bayesian composite score mapped to HUD NSPIRE-equivalent rating scale (0-100)",
"assessed_at": "2026-04-20T14:30:00.000Z"
}
| Score | Grade | Rating |
|---|---|---|
| 90–100 | A | GOOD |
| 80–89 | B | GOOD or FAIR |
| 70–79 | C | FAIR or FAIL |
| 60–69 | D | FAIL |
| 0–59 | F | FAIL |
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededReplacement Cost Valuation for insurance. Returns total replacement cost by system category, per-unit RCV, critical and warning exposure, and (when estimated_value is set on the property) deferred maintenance as a percentage of property value. Insurance carriers use this for coverage adequacy and claim reserve estimates.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/rcv \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"unit_count": 24,
"total_replacement_cost": 89200,
"rcv_per_unit": 3717,
"critical_exposure": 7200,
"warning_exposure": 9800,
"systems": [
{ "system": "hvac_central", "total_rcv": 32000, "components": 16, "critical": 1, "warning": 3 },
{ "system": "water_heater_gas", "total_rcv": 18500, "components": 12, "critical": 1, "warning": 2 },
{ "system": "refrigerator", "total_rcv": 14200, "components": 8, "critical": 0, "warning": 1 }
],
"estimated_value": 4200000,
"deferred_as_pct_of_value": "0.3%",
"assessed_at": "2026-04-20T14:30:00.000Z"
}
deferred_as_pct_of_value Is NullIf the property record has no estimated_value field set, deferred_as_pct_of_value is returned as null. Set estimated_value on the property via PUT /v1/properties/{id} to populate this field.
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededMandatory inspection tracker. Returns compliance items (annual boiler inspections, elevator inspections, fire suppression certifications, etc.) with due dates sourced from NFPA 25, ASME A17.1, NEC, and state-level regulatory frameworks. Shows overdue, due-soon, upcoming, and OK status.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/compliance \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"compliance_items": [
{
"appliance_id": "A_elev01",
"appliance_type": "elevator",
"brand": "Otis",
"inspection_type": "Annual Certification",
"authority": "ASME A17.1",
"mandatory": true,
"interval_months": 12,
"last_inspection": "2025-03-10",
"due_date": "2026-03-10",
"days_until_due": -41,
"status": "OVERDUE"
},
{
"appliance_id": "A_boil01",
"appliance_type": "boiler",
"inspection_type": "Annual Safety Inspection",
"authority": "State boiler code",
"mandatory": true,
"interval_months": 12,
"due_date": "2026-05-15",
"days_until_due": 25,
"status": "DUE_SOON"
}
],
"overdue": 1,
"partner": "AppFolio"
}
| Status | Window |
|---|---|
OVERDUE | days_until_due < 0 |
DUE_SOON | 0 to 30 days |
UPCOMING | 31 to 90 days |
OK | 91+ days |
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededList insurance claims for a property. Returns every insurance claim attached to this property, sorted by date of loss (newest first). Each claim records its type, date, amount, carrier, and the scoring impact multiplier it currently contributes.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Records per page |
offset | integer | 0 | Records to skip |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/claims \
-H "X-Api-Key: fv_live_XXX"
{
"claims": [
{
"id": "CLM_abc123",
"property_id": "P_abc123",
"claim_type": "water_damage",
"date_of_loss": "2024-09-15",
"claim_number": "CLM-2024-0412",
"carrier": "State Farm",
"amount_paid": 4200,
"description": "Water heater rupture flooded unit 3B",
"status": "closed",
"scoring_impact": 1.5,
"created_at": "2024-10-01T10:00:00.000Z"
}
],
"total": 1,
"limit": 50,
"offset": 0,
"property_id": "P_abc123",
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededClaims scoring impact with recency decay. For each claim on a property, returns the base likelihood ratio, the currently-effective likelihood ratio (after recency decay), the claim's age in years, and which appliance systems are affected. Use this to explain to underwriters exactly how much weight each claim carries in the risk score.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
curl https://platform.investwisecap.com/api/v1/property/P_abc123/claims/impact \
-H "X-Api-Key: fv_live_XXX"
{
"property_id": "P_abc123",
"name": "Maple Ridge Apartments",
"total_claims": 2,
"active_claims": 1,
"expired_claims": 1,
"claims": [
{
"claim_id": "CLM_abc123",
"claim_type": "water_damage",
"label": "Water Damage / Flooding",
"date_of_loss": "2024-09-15",
"age_years": 1.6,
"base_likelihood_ratio": 1.5,
"effective_likelihood_ratio": 1.34,
"decay_remaining_years": 3.4,
"status": "active_scoring",
"affected_systems": [ "water_heater_gas", "plumbing_system" ],
"affected_components_count": 11
},
{
"claim_id": "CLM_def456",
"claim_type": "fire_electrical",
"age_years": 6.2,
"base_likelihood_ratio": 1.4,
"effective_likelihood_ratio": 1.0,
"decay_remaining_years": 0,
"status": "expired_no_impact"
}
],
"methodology": {
"version": "1.0",
"recency_decay": { "decay_years": 5 },
"max_claims_scored": 3
},
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededList scored components. Returns components with current risk tier, risk score, and basic identifying metadata. Supports filtering by property, appliance, or risk tier. Useful for building tables of "everything at risk" across a portfolio or drilling into a specific appliance.
| Param | Type | Default | Description |
|---|---|---|---|
property_id | string | — | Limit to components at a specific property |
appliance_id | string | — | Limit to components of a specific appliance |
tier | string | — | CRITICAL · WARNING · GOOD |
limit | integer | 50 | Records per page (max 200) |
offset | integer | 0 | Records to skip |
sandbox | string | — | true for demo data only |
curl "https://platform.investwisecap.com/api/v1/components?tier=CRITICAL" \
-H "X-Api-Key: fv_live_XXX"
{
"components": [
{
"id": "C_def456",
"component_name": "Anode Rod",
"component_def_id": "wh_gas_anode",
"appliance_id": "A_ghi789",
"appliance_type": "water_heater_gas",
"property_id": "P_abc123",
"property_name": "Maple Ridge Apartments",
"risk_score": 0.847,
"risk_tier": "CRITICAL",
"confidence": "HIGH",
"age_years": 12,
"projected_failure_year": 2026
}
],
"total": 47,
"limit": 50,
"offset": 0,
"partner": "AppFolio"
}
proactive_cost and reactive_cost are not included by default. Use GET /v1/property/{id}/report or /v1/property/{id}/rcv when you need financial figures.
401 — Missing or invalid credentials429 — Rate limit exceededService event history for a single component. Returns every service event attached to this component (preventive maintenance, repairs, replacements, inspections) with dates, costs, technicians, and notes. Useful for auditing maintenance history before underwriting or due diligence.
| Param | Type | Description |
|---|---|---|
id | string | Component ID (e.g., C_def456) |
curl https://platform.investwisecap.com/api/v1/components/C_def456/history \
-H "X-Api-Key: fv_live_XXX"
{
"component": {
"id": "C_def456",
"component_name": "Anode Rod",
"appliance_id": "A_ghi789",
"appliance_type": "water_heater_gas",
"install_year": 2014,
"last_replaced": null,
"last_serviced": "2025-09-10"
},
"events": [
{
"id": "SE_001",
"event_type": "Inspection",
"date": "2025-09-10",
"technician": "Mike Torres",
"total_cost": 95,
"notes": "Minor corrosion observed. Schedule replacement within 6 months.",
"condition_after": "fair"
}
],
"total_events": 1,
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Component not found429 — Rate limit exceededDaily risk score time series. Returns the component's risk score for each day it has been tracked (daily snapshot at 3 AM UTC). Retained for 365 days. Use this to plot a trend chart or detect sharp risk-score increases that may signal a cascading failure.
| Param | Type | Description |
|---|---|---|
id | string | Component ID |
| Param | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Data points per page (max 200) |
offset | integer | 0 | Data points to skip |
curl "https://platform.investwisecap.com/api/v1/components/C_def456/trend?limit=90" \
-H "X-Api-Key: fv_live_XXX"
{
"component_id": "C_def456",
"trend": [
{ "date": "2026-01-20", "risk_score": 0.724, "risk_tier": "WARNING" },
{ "date": "2026-01-21", "risk_score": 0.728, "risk_tier": "WARNING" },
{ "date": "2026-02-15", "risk_score": 0.781, "risk_tier": "CRITICAL" },
{ "date": "2026-04-20", "risk_score": 0.847, "risk_tier": "CRITICAL" }
],
"total": 90,
"limit": 90,
"offset": 0,
"partner": "AppFolio"
}
401 — Missing or invalid credentials404 — Component not found429 — Rate limit exceededActive CRITICAL and WARNING components. Returns a single consolidated list of every at-risk component in the portfolio, sorted by risk score descending. The most direct query for "what needs attention right now" use cases.
| Param | Type | Default | Description |
|---|---|---|---|
property_id | string | — | Limit to alerts for one property |
limit | integer | 50 | Records per page (max 200) |
offset | integer | 0 | Records to skip |
sandbox | string | — | true for demo data only |
curl https://platform.investwisecap.com/api/v1/alerts \
-H "X-Api-Key: fv_live_XXX"
{
"alerts": [
{
"component_id": "C_def456",
"component_name": "wh_gas_anode",
"appliance_type": "water_heater_gas",
"property_id": "P_abc123",
"property_name": "Maple Ridge Apartments",
"property_address": "123 Main St",
"risk_score": 0.847,
"risk_tier": "CRITICAL"
}
],
"total": 47,
"limit": 50,
"offset": 0,
"critical_count": 12,
"warning_count": 35,
"partner": "AppFolio"
}
401 — Missing or invalid credentials429 — Rate limit exceededChange event stream (polling alternative to webhooks). See Section 10 for the full usage pattern and returned event types.
| Param | Type | Required | Description |
|---|---|---|---|
since | string (ISO 8601) | Required | Returns events after this timestamp |
limit | integer | Optional | Default 50, max 200 |
offset | integer | Optional | Default 0 |
curl "https://platform.investwisecap.com/api/v1/events?since=2026-04-15T00:00:00Z" \
-H "X-Api-Key: fv_live_XXX"
400 — Missing since or invalid timestamp format401 — Missing or invalid credentials429 — Rate limit exceededData plate photos for an appliance. Returns URLs to every photo captured for this appliance (brand/model/serial label photos uploaded during walk-throughs and photos attached to service events). Useful for insurance documentation, underwriting support, and visual audits.
| Param | Type | Description |
|---|---|---|
id | string | Appliance ID |
curl https://platform.investwisecap.com/api/v1/appliances/A_ghi789/photos \
-H "X-Api-Key: fv_live_XXX"
{
"appliance_id": "A_ghi789",
"type": "water_heater_gas",
"brand": "Rheem",
"model": "XG50T06EC36U1",
"service_event_photos": [
{
"filename": "SE_001_1726920000000.jpg",
"original_name": "data-plate.jpg",
"url": "/api/uploads/SE_001_1726920000000.jpg",
"uploaded_at": "2025-09-10T14:00:00.000Z",
"service_event_id": "SE_001",
"event_type": "Inspection",
"event_date": "2025-09-10"
}
],
"appliance_photos": [],
"total": 1
}
X-Api-Key header — never include credentials in an <img src> attribute.
401 — Missing or invalid credentials404 — Appliance not found429 — Rate limit exceededWrite endpoints create or modify resources. All write endpoints consume application/json request bodies. All support the Idempotency-Key header where noted. Write operations count against your daily rate limit.
Exchange client credentials for a bearer token. This is the OAuth 2.0 client credentials flow. The issued token is valid for 1 hour and grants the same access scope as an API key.
| Field | Type | Required | Description |
|---|---|---|---|
grant_type | string | Required | Must be "client_credentials" |
client_id | string | Required | Your OAuth client ID |
client_secret | string | Required | Your OAuth client secret |
curl -X POST https://platform.investwisecap.com/api/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"client_credentials","client_id":"your_id","client_secret":"your_secret"}'
{
"access_token": "fvt_7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write",
"partner": "AppFolio"
}
400 — grant_type is not client_credentials, or missing fields401 — Invalid client_id or client_secretCreate a property. Registers a new property in the ForVue system. Units are auto-generated from unit_count. Use partner_property_id to store your system's ID for cross-referencing.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Required | Display name |
address | string | Required | Street address |
state | string | Required | US state abbreviation (e.g., KY) |
city | string | Optional | City name |
zip | string | Optional | ZIP code (used for EDI climate scoring) |
unit_count | integer | Optional | Number of rental units (auto-creates unit records) |
year_built | integer | Optional | Construction year |
notes | string | Optional | Free-form notes |
partner_property_id | string | Optional | Your external system ID for cross-reference |
curl -X POST https://platform.investwisecap.com/api/v1/properties \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: appfolio-prop-12345-create" \
-d '{
"name": "Riverside Commons",
"address": "456 River Rd",
"city": "Louisville",
"state": "KY",
"zip": "40202",
"unit_count": 16,
"partner_property_id": "AF-PROP-12345"
}'
{
"id": "P_xyz789",
"name": "Riverside Commons",
"address": "456 River Rd",
"city": "Louisville",
"state": "KY",
"zip": "40202",
"unit_count": 16,
"partner_property_id": "AF-PROP-12345",
"created_at": "2026-04-20T14:30:00.000Z"
}
400 — Missing required fields (name, address, state)401 — Missing or invalid credentials429 — Rate limit exceededUpdate a property. Merges the provided fields into the existing property record. Unspecified fields remain unchanged.
Any field from the create endpoint. All fields are optional on update.
curl -X PUT https://platform.investwisecap.com/api/v1/properties/P_xyz789 \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-d '{"estimated_value": 3800000, "notes": "Updated from AppFolio sync"}'
Returns the full updated property object.
401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededCreate an appliance. Adds a single appliance to a property. Components are automatically generated from the Knowledge Base based on type_id — no manual component creation needed. Scoring begins immediately.
| Field | Type | Required | Description |
|---|---|---|---|
property_id | string | Required | Parent property |
type_id | string | Required | Appliance type from KB (see Appendix) |
install_year | integer | Required | Year appliance was installed |
unit_number | string | Optional | Unit identifier (matched to existing unit record) |
brand | string | Optional | Manufacturer name (matched to KB brand tiers) |
model | string | Optional | Model number |
serial | string | Optional | Serial number |
brand_tier | string | Optional | premium · standard · budget (default: standard) |
usage_intensity | number | Optional | 0.5–2.0 (default: 1.0) |
notes | string | Optional | Free-form notes |
partner_appliance_id | string | Optional | Your external system ID |
curl -X POST https://platform.investwisecap.com/api/v1/appliances \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: appfolio-appl-unit3-hvac" \
-d '{
"property_id": "P_abc123",
"type_id": "hvac_central",
"install_year": 2016,
"brand": "Carrier",
"brand_tier": "premium",
"unit_number": "3",
"partner_appliance_id": "AF-EQUIP-789"
}'
{
"appliance": {
"id": "A_new123",
"property_id": "P_abc123",
"type_id": "hvac_central",
"brand": "Carrier",
"install_year": 2016,
"brand_tier": "premium",
"created_at": "2026-04-20T14:30:00.000Z"
},
"components": [
{ "id": "C_001", "component_def_id": "hvac_compressor" },
{ "id": "C_002", "component_def_id": "hvac_evap_coil" },
{ "id": "C_003", "component_def_id": "hvac_cond_coil" }
]
}
400 — Missing required fields (property_id, type_id, install_year)401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededUpdate an appliance. Merges provided fields into the existing record. Useful for correcting brand, model, or install year after initial import. Scores recalculate automatically on the next scoring pass.
curl -X PUT https://platform.investwisecap.com/api/v1/appliances/A_new123 \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-d '{"brand": "Carrier Infinity", "model": "24ACC636A003"}'
Returns the full updated appliance object.
401 — Missing or invalid credentials404 — Appliance not found429 — Rate limit exceededDelete an appliance. Permanently removes an appliance and all its components, risk snapshots, and associated data. This action is irreversible.
curl -X DELETE https://platform.investwisecap.com/api/v1/appliances/A_new123 \
-H "X-Api-Key: fv_live_XXX"
{ "ok": true }
401 — Missing or invalid credentials404 — Appliance not found429 — Rate limit exceededBulk-create appliances for a single property. Accepts up to 100 appliances per call. Partial success is supported — successful records are created and failed records are returned with error details so you can fix and retry.
| Field | Type | Required | Description |
|---|---|---|---|
property_id | string | Required | Target property (applies to all appliances in batch) |
appliances | array | Required | Array of appliance objects (max 100) |
curl -X POST https://platform.investwisecap.com/api/v1/appliances/bulk \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: appfolio-bulk-prop-abc123-2026-04-20" \
-d '{
"property_id": "P_abc123",
"appliances": [
{"type_id":"hvac_central","brand":"Carrier","install_year":2018,"unit_number":"1"},
{"type_id":"water_heater_gas","brand":"Rheem","install_year":2015,"unit_number":"1"},
{"type_id":"refrigerator","brand":"LG","install_year":2020,"unit_number":"1"}
]
}'
{
"created": 3,
"errors": 0,
"appliances": [
{ "id": "A_001", "type_id": "hvac_central" },
{ "id": "A_002", "type_id": "water_heater_gas" },
{ "id": "A_003", "type_id": "refrigerator" }
],
"error_details": []
}
{
"created": 2,
"errors": 1,
"appliances": [ /* 2 created records */ ],
"error_details": [
{ "index": 1, "error": "type_id required" }
]
}
/appliances/bulk over many individual POST /v1/appliances calls. One bulk call uses one rate-limit quota slot; 100 individual calls use 100.
400 — Missing property_id or appliances array; array exceeds 100401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededBulk-update properties. Accepts up to 50 property updates per call. Each entry must include an id; remaining fields are merged into the existing record. Unrecognized IDs are returned as errors.
| Field | Type | Required | Description |
|---|---|---|---|
properties | array | Required | Array of property update objects (max 50) |
Each object in properties must have:
id (required) — the property to updatecurl -X PUT https://platform.investwisecap.com/api/v1/properties/bulk \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-d '{
"properties": [
{"id":"P_abc123","estimated_value":4200000},
{"id":"P_def456","unit_count":32,"estimated_value":6500000}
]
}'
{
"updated": 2,
"errors": 0,
"properties": [ /* 2 updated records */ ],
"error_details": []
}
400 — Missing properties array; array exceeds 50401 — Missing or invalid credentials429 — Rate limit exceededBulk-import service events. Accepts up to 100 service events per call. Essential for syncing historical work-order data from property management software. Events fire the service_event.created webhook. Events that reset a component's age clock (event_type: "Replacement") trigger immediate re-scoring.
| Field | Type | Required | Description |
|---|---|---|---|
events | array | Required | Array of service event objects (max 100) |
Each event object requires:
| Field | Type | Required | Description |
|---|---|---|---|
appliance_id | string | Required | Target appliance |
event_type | string | Required | See Section 7.2 for valid values |
date | string (YYYY-MM-DD) | Required | Event date |
component_id | string | Optional | Specific component (scopes event to one part) |
technician | string | Optional | Technician or vendor name |
parts_cost | number | Optional | Parts cost in USD |
labor_cost | number | Optional | Labor cost in USD |
notes | string | Optional | Free-form notes (scanned for risk keywords) |
condition_after | string | Optional | good · fair · poor |
curl -X POST https://platform.investwisecap.com/api/v1/service-events/bulk \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: appfolio-workorders-2026-04-batch1" \
-d '{
"events": [
{
"appliance_id": "A_ghi789",
"event_type": "Preventive Maintenance",
"date": "2026-03-15",
"technician": "ABC Plumbing",
"parts_cost": 85, "labor_cost": 210,
"notes": "Annual water heater flush and anode inspection"
},
{
"appliance_id": "A_new123",
"event_type": "Repair",
"date": "2026-04-02",
"parts_cost": 0, "labor_cost": 150,
"notes": "HVAC blower motor capacitor replaced"
}
]
}'
{
"created": 2,
"errors": 0,
"events": [
{ "id": "SE_new001", "event_type": "Preventive Maintenance", "total_cost": 295 },
{ "id": "SE_new002", "event_type": "Repair", "total_cost": 150 }
],
"error_details": []
}
400 — Missing events array; array exceeds 100401 — Missing or invalid credentials429 — Rate limit exceededImport insurance claims for a property. Accepts a batch of claims that feed into the Bayesian scoring engine as evidence of elevated system-specific risk. Recency decay applies: claims older than 5 years contribute no scoring impact.
| Param | Type | Description |
|---|---|---|
id | string | Property ID |
| Field | Type | Required | Description |
|---|---|---|---|
claims | array | Required | Array of claim objects |
Each claim object requires:
| Field | Type | Required | Description |
|---|---|---|---|
claim_type | string | Required | One of: water_damage, fire_electrical, hvac_mechanical, roof_weather, appliance_liability, general_property |
date_of_loss | string (YYYY-MM-DD) | Required | Date the loss occurred |
claim_number | string | Optional | Carrier's claim number |
carrier | string | Optional | Insurance carrier name |
amount_paid | number | Optional | Paid amount in USD |
description | string | Optional | Free-form description |
status | string | Optional | open · closed (default: closed) |
curl -X POST https://platform.investwisecap.com/api/v1/property/P_abc123/claims \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: statefarm-import-P_abc123-batch3" \
-d '{
"claims": [
{
"claim_type": "water_damage",
"date_of_loss": "2024-09-15",
"claim_number": "CLM-2024-0412",
"carrier": "State Farm",
"amount_paid": 4200,
"description": "Water heater tank rupture, unit 3B flooded",
"status": "closed"
}
]
}'
{
"created": 1,
"errors": 0,
"claims": [
{
"id": "CLM_new001",
"claim_type": "water_damage",
"date_of_loss": "2024-09-15",
"scoring_impact": 1.5,
"created_at": "2026-04-20T14:30:00.000Z"
}
],
"error_details": []
}
400 — Missing claims array or invalid claim_type401 — Missing or invalid credentials404 — Property not found429 — Rate limit exceededSubmit a raw sensor or meter event. The simplest IoT ingestion endpoint — records the event and triggers re-scoring of the affected appliance's components. Use when you already know the property_id and appliance_id.
| Field | Type | Required | Description |
|---|---|---|---|
event_type | string | Required | One of the 9 service event types, or a sensor-specific type (e.g., "Leak Detected") |
property_id | string | Optional* | Target property (required if no address) |
appliance_id | string | Optional | Target appliance (if known) |
address | string | Optional* | Property address (required if no property_id) |
sensor_value | number | Optional | Raw reading from sensor |
unit | string | Optional | Measurement unit (e.g., "PSI", "°F", "gallons") |
notes | string | Optional | Free-form description from the sensor or installer |
partner_property_id | string | Optional | Your external ID for cross-reference |
curl -X POST https://platform.investwisecap.com/api/v1/meter-event \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sensor-device-A7F2-event-1713620400" \
-d '{
"property_id": "P_abc123",
"appliance_id": "A_ghi789",
"event_type": "Pressure Spike",
"sensor_value": 145,
"unit": "PSI",
"notes": "Pressure sensor reading exceeded safe threshold"
}'
{
"event_id": "PE_001",
"property_id": "P_abc123",
"appliance_id": "A_ghi789",
"event_type": "Pressure Spike",
"recorded_at": "2026-04-20T14:30:00.000Z"
}
400 — Missing event_type or neither property_id nor address provided401 — Missing or invalid credentials429 — Rate limit exceededSmart meter event with auto-creation. The full IoT ingestion flow — if the target property or appliance doesn't exist, ForVue creates them from the address and appliance metadata you provide. This means a sensor can be installed first and register itself on first read. Returns an immediate risk summary after re-scoring.
| Field | Type | Required | Description |
|---|---|---|---|
address | string | Required | Property address — used to locate or create the property |
state | string | Required | US state abbreviation |
event_type | string | Required | Event type (service event or sensor-specific) |
city, zip | string | Optional | Supplementary address fields (improve EDI scoring if included) |
unit_count | integer | Optional | Unit count if a new property is being created |
unit_number | string | Optional | Specific unit for the appliance |
appliance_type_id | string | Optional | KB appliance type (auto-creates appliance if not found) |
appliance_brand | string | Optional | Brand (fuels auto-create) |
appliance_install_year | integer | Optional | Install year (fuels auto-create) |
sensor_value, unit, notes | various | Optional | Sensor metadata (same as basic meter event) |
partner_property_id, partner_appliance_id | string | Optional | Your external IDs |
curl -X POST https://platform.investwisecap.com/api/v1/meter-event/smart \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sensor-XYZ123-reading-2026-04-20T14:30" \
-d '{
"address": "789 Oak Ave",
"city": "Louisville",
"state": "KY",
"zip": "40203",
"unit_count": 12,
"unit_number": "2",
"appliance_type_id": "water_heater_gas",
"appliance_brand": "Rheem",
"appliance_install_year": 2018,
"event_type": "Leak Detected",
"sensor_value": 1,
"unit": "binary",
"notes": "Moisture sensor triggered under water heater"
}'
{
"event_id": "PE_002",
"property": {
"id": "P_auto001",
"address": "789 Oak Ave",
"was_created": true
},
"appliance": {
"id": "A_auto002",
"type_id": "water_heater_gas",
"was_created": true
},
"risk_summary": {
"components_scored": 6,
"critical_count": 2,
"warning_count": 2,
"good_count": 2
},
"recorded_at": "2026-04-20T14:30:00.000Z"
}
400 — Missing address, state, or event_type401 — Missing or invalid credentials429 — Rate limit exceededSmart meter v2 — adds callbacks and webhooks. Identical to /v1/meter-event/smart but additionally: (a) fires sensor.smart, property.created, appliance.created, and component-tier webhooks to all subscribed partners; (b) optionally invokes a one-time callback URL supplied in the request.
| Field | Type | Required | Description |
|---|---|---|---|
callback_url | string | Optional | One-time HTTPS URL that receives the response payload after processing |
The callback is signed using the same HMAC-SHA256 scheme as webhooks (see Section 9). The callback fires asynchronously; the HTTP response is returned immediately.
curl -X POST https://platform.investwisecap.com/api/v1/meter-event/smart/v2 \
-H "X-Api-Key: fv_live_XXX" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sensor-XYZ123-reading-v2-2026-04-20" \
-d '{
"address": "789 Oak Ave",
"state": "KY",
"event_type": "Leak Detected",
"appliance_type_id": "water_heater_gas",
"appliance_install_year": 2018,
"callback_url": "https://sensors.partner.com/forvue-ack/XYZ123"
}'
Same shape as /v1/meter-event/smart. Same payload is also POSTed to callback_url (when provided) and broadcast via webhooks.
sensor.smart, property.created, appliance.created, and per-component component.critical/component.warning events). Design your webhook receiver to dedupe by event_id + component_id.
400 — Missing required fields401 — Missing or invalid credentials429 — Rate limit exceededThis section exists because ForVue's scoring engine, Knowledge Base, brand-tier tables, likelihood-ratio mappings, and cascade rules are the result of years of calibration against ASHRAE, HUD, NAHB, NFPA, ISO, IBHS, and manufacturer data. They are a material trade secret and a core competitive advantage. Partners who gain access to the API accept specific obligations to protect this information.
As an API Partner, you agree to:
401 responses by re-authenticating rather than failing permanently.Per the Partnership Agreement and Terms of Service §6.8, you may not:
A "competing product or service" includes, without limitation: any software that produces appliance-level or component-level failure probability scores, any system that generates reserve recommendations or Capital Needs Assessments derived from predictive failure modeling, and any integration that replicates ForVue's Weibull-Bayesian methodology on real estate or facility data.
ForVue retains logs of every authenticated API call including timestamp, partner identity, endpoint, response time, and response status. These logs are used for:
Suspicious access patterns — including but not limited to systematic pagination across all properties, repeated fetches of the same component, or unusual geographic distribution of source IPs — trigger automatic alerts to the Wise Capital security team. Persistent violations result in immediate credential revocation.
Upon termination of your Partnership Agreement (for any reason):
Reports generated through the API (Bank Origination, Insurance Policy Inception, HUD CNA, Deal Analysis) include ForVue branding, patent notice (USPTO App. 64/032,704), and methodology citation. Partners distributing these Reports to third parties must preserve these notices intact. You may not remove attribution to Wise Capital or present Reports as your own work product.
Valid values for type_id when creating appliances. The Knowledge Base ships with 30 appliance types covering 169 components today; the full set of supported type_ids is listed below. The KB itself (component lifespans, manufacturer service bulletin lookups, error-code library, parts catalog) is updated in place; the public type_id list is stable.
| type_id | Display Name | System Category |
|---|---|---|
hvac_central | Central HVAC | HVAC |
hvac_heat_pump | Heat Pump | HVAC |
hvac_mini_split | Mini-Split / Ductless HVAC | HVAC |
water_heater_gas | Gas Water Heater | Plumbing |
water_heater_electric | Electric Water Heater | Plumbing |
water_heater_tankless | Tankless Water Heater | Plumbing |
boiler | Boiler | HVAC |
wall_furnace | Wall Furnace | HVAC |
electric_baseboard | Electric Baseboard Heater | HVAC |
refrigerator | Refrigerator | Appliance |
washer | Clothes Washer | Appliance |
dryer | Clothes Dryer | Appliance |
dishwasher | Dishwasher | Appliance |
oven_range | Oven / Range | Appliance |
microwave | Microwave | Appliance |
garbage_disposal | Garbage Disposal | Plumbing |
sump_pump | Sump Pump | Plumbing |
plumbing_system | Plumbing System | Plumbing |
electrical_panel | Electrical Panel | Electrical |
gfci_outlets | GFCI Outlets | Electrical |
smoke_detector | Smoke / CO Detector | Safety |
fire_suppression | Fire Suppression System | Safety |
elevator | Elevator | Mechanical |
pool_equipment | Pool / Spa Equipment | Amenity |
roof | Roof | Structure |
garage_door | Garage Door | Mechanical |
water_softener | Water Softener / Filtration | Plumbing |
window_ac | Window AC Unit | HVAC |
ductwork | Ductwork System | HVAC |
Additional types may be added in future Knowledge Base versions. Always check GET /kb/appliance-types (available via admin endpoints) for the current authoritative list.
| claim_type | Description | Affected Systems | Base LR |
|---|---|---|---|
water_damage | Plumbing leaks, burst pipes, appliance leaks | Plumbing, water heaters, washer | 1.50 |
fire_electrical | Electrical fires, panel failures, wiring | Electrical panel, dryer, HVAC | 1.45 |
hvac_mechanical | HVAC system failures, compressor loss | HVAC, heat pump, boiler | 1.35 |
roof_weather | Storm damage, hail, wind, leaks from roof | Roof, attic, ceiling damage | 1.40 |
appliance_liability | Appliance-caused damage or injury | All major appliances | 1.25 |
general_property | Structural, fixture, or other property damage | All systems (weak signal) | 1.15 |
Likelihood ratios decay linearly from the base value to 1.0 over 5 years from the date of loss. Only the 3 most recent claims per property contribute to scoring.
| event_type | Effect on Scoring | Webhooks Fired |
|---|---|---|
Preventive Maintenance | May lower risk on at-risk components | service_event.created |
Inspection | Neutral; improves confidence | service_event.created |
Filter Change | Positive (HVAC/water specific) | service_event.created |
Cleaning | Positive | service_event.created |
Repair | Adds recent-repair risk factor | service_event.created |
Replacement | Resets age clock; re-scores | service_event.created, possible component.recovered |
Emergency Repair | High-weight failure signal | service_event.created, possible tier changes |
Warranty Claim | Neutral; informational | service_event.created |
Other | Neutral; informational | service_event.created |
This document is version 2.0 of the reference (July 9, 2026), describing ForVue Partner API v1. Future versions will:
/v2 without breaking v1 behaviorThe authoritative machine-readable spec is at GET /v1/openapi.json. If any detail in this reference conflicts with the live OpenAPI spec, the spec wins.
NUMERIC, DECIMAL, BIGINT, and INT8 fields as JSON numbers, not JSON strings. This applies to every dollar amount, risk score, unit count, and count field returned by any /v1 endpoint. If your integration parses these fields with parseFloat() or parseInt(), no change is required. If your integration compares any of these fields to string literals (e.g. value === "2.50") or concatenates them expecting string semantics, update to number semantics before consuming v2 responses. Verify with a call to any endpoint returning a monetary field (for example GET /v1/property/{id}/reserve).
Other v1.0 → v2.0 changes:
GET /v1/auth/methods, GET /v1/property/{id}/compliance, GET /v1/components/{id}/trend, PUT /v1/properties/{id}, and DELETE /v1/appliances/{id}. These endpoints were all live in v1.0 but were not fully documented; sections have been added rather than the endpoints changing.| Reason | Contact | Expected Response |
|---|---|---|
| Credentials, onboarding, partnership terms | wise@investwisecap.com | Within 2 business days |
| API bug reports or unexpected behavior | wise@investwisecap.com | Within 1 business day |
| Suspected credential compromise | wise@investwisecap.com | Within 24 hours — escalate urgent |
| Webhook delivery issues | wise@investwisecap.com | Within 1 business day |
| Rate limit increase requests | wise@investwisecap.com | Business agreement required |
| Field | Value |
|---|---|
| Document | ForVue Partner API Reference |
| Version | 2.0 |
| Effective | July 9, 2026 |
| Publisher | Wise Capital, LLC · Louisville, Kentucky |
| Patent | USPTO Application 64/032,704 (pending) |
| Copyright | © 2026 Wise Capital, LLC. All rights reserved. |
| Classification | Confidential & Proprietary — for authorized API Partners only |