Build for production

Retry safely

Keep the same Idempotency-Key when you retry one logical call.

Choose a key

The header is optional, and absence is never an error. Without it, every send is a new, charged request.

Keys are scoped to your account, the record that owns your keys and balance, the money available for API calls. One account cannot replay another account's result.

Use 255 characters or fewer, no control characters, and a value that is not blank. Tabs, carriage returns and line feeds are control characters.

Invalid keys receive 400 invalid-request before anything is charged. Keys are never trimmed; surrounding spaces make keys different.

Before: send the call

Choose one key for this request and keep its body and endpoint with it. Keep every body byte the same, including spaces and JSON field order.

curl https://api.investorliftdata.com/v1/predict \ --request POST --max-time 30 \ --header "Authorization: Bearer $INVESTORLIFT_API_KEY" \ --header "Content-Type: application/json" \ --header "Idempotency-Key: property-42-v1" \ --data '{"address": "1026 N Beckley Ave, Dallas, TX 75203"}'

After: retry the same call

If the answer is lost, resend this exact body and endpoint with the same key. A stored success is replayed without another charge.

curl https://api.investorliftdata.com/v1/predict \ --request POST --max-time 30 \ --header "Authorization: Bearer $INVESTORLIFT_API_KEY" \ --header "Content-Type: application/json" \ --header "Idempotency-Key: property-42-v1" \ --data '{"address": "1026 N Beckley Ave, Dallas, TX 75203"}'
Show the full response (145 lines)
JSONFull response
{ "comps": [ { "sqft": 2080, "lotsize": 6500, "bedrooms": 6, "bathrooms": 2, "sale_date": "2024-12-03", "sale_price": 246641, "year_built": 1945, "address_zip": "75203", "property_id": "00000000000000000000000000000001", "address_city": "Dallas", "address_state": "TX", "property_type": "Single Family", "address_street": "523 N Marsalis Ave", "distance_miles": 0.4, "similarity_rank": 1, "price_per_square_foot": 119 }, { "sqft": 1400, "lotsize": 7025, "bedrooms": 3, "bathrooms": 1, "sale_date": "2026-05-08", "sale_price": 234999, "year_built": 1930, "address_zip": "75203", "property_id": "00000000000000000000000000000001", "address_city": "Dallas", "address_state": "TX", "property_type": "Single Family", "address_street": "102 E 5th St", "distance_miles": 0.09, "similarity_rank": 2, "price_per_square_foot": 168 }, { "sqft": 1787, "lotsize": 6678, "bedrooms": 4, "bathrooms": 2, "sale_date": "2025-03-05", "sale_price": 503139, "year_built": 1945, "address_zip": "75208", "property_id": "00000000000000000000000000000001", "address_city": "Dallas", "address_state": "TX", "property_type": "Single Family", "address_street": "818 Elsbeth St", "distance_miles": 0.24, "similarity_rank": 3, "price_per_square_foot": 282 } ], "comp_band": { "low": 388634, "high": 942020, "median": 571412 }, "cost_stack": { "loan": 331200, "points": 6624, "interest": 6533, "hold_days": 60, "down_payment": 82800, "closing_costs": 29562, "target_profit": 114282 }, "rehab_budget": 0, "target_margin": 0.2, "valuation_mean": 1016099, "subject_property": { "facts": { "bathrooms": { "value": 2, "source": "county-record" }, "year_built": { "value": 1935, "source": "county-record" }, "square_feet": { "value": 2047, "source": "county-record" }, "property_type": { "value": "Single Family", "source": "county-record" }, "lot_size_square_feet": { "value": 7100, "source": "county-record" } }, "address": { "zip": "75203", "city": "Dallas", "state": "TX", "street": "1026 N Beckley Ave" }, "property_id": "00000000000000000000000000000001", "address_quality": { "code": "zip-confirmed", "statement": "The house number matched exactly one county record, and that record sits in the same ZIP code your address resolved to. Check the address and property facts in this block before relying on these numbers." }, "outside_model_range": { "flagged": false, "reasons": [] } }, "as_is_similar_band": { "basis": "all-comparable-sales", "statement": "Too few comparable sales passed the size, age and recency filter this service applies to state a similar-sales range, so this price-per-square-foot range covers every comparable sale below that carries a usable sale price and square footage. `qualifying_sales` is how many passed the filter and fell short.", "qualifying_sales": 1, "price_per_square_foot": { "low": 190, "high": 460, "median": 279 } }, "rehab_adjusted_arv": 571000, "max_allowable_offer": { "amount": 414000, "clamped": false }, "valuation_quantiles": { "0.02": 191787, "0.10": 345336, "0.20": 476815, "0.30": 598093, "0.40": 733771, "0.50": 878872, "0.60": 1110818, "0.70": 1417051, "0.80": 1988162, "0.90": 3615373, "0.98": 15505619 }, "effective_sample_size": 51.04950714111328, "model_estimate_available": true, "pricing_model_arv_estimate": 1417000 }

Reuse a key correctly

The replay window is 24 hours; see the formal rules. Inside it, the same request and key return the stored response. After 24 hours, the stored response expires and a repeat is a new, charged request.

Only successful responses are stored. A key is replayed only when the earlier call succeeded and its response was stored.

If the earlier call was refunded, ended without a stored response, or is older than the replay window, the key is taken over. The new request runs and is charged, whatever body it carries. Retrying after a failed or refunded 502 or 504 is a fresh attempt that spends again.

Only while an earlier success remains stored does a different body or endpoint cause 422 idempotency-key-conflict. Nothing is charged for that refusal; use a new key for the changed request.

An identical request still running receives 409 duplicate-request-in-flight, with no charge for the copy. Wait for its Retry-After interval, then ask again with the same key.

The Terms-consent check runs before any key lookup, including a replay. If current Terms need acceptance, 403 terms-not-accepted refuses the send without a charge. Accepting them restores the replay while its window remains open.

The free POST /v1/validate call ignores Idempotency-Key entirely. See Test without spending for its availability rules.

The API never retries for you. A charged call, an API request with a price, can fail after it is charged, so you control each new attempt.

Next steps

Last modified on