Valuation API

A reproducible reference value for any property in the City of Buenos Aires, with a confidence range, comparables and an explanation in plain language. Base URL: https://api.zavaluo.com/v1. Every response is JSON in UTF-8.

Market available: CABA (sale and rent). Costa del Sol (Spain) later; the country field on every request anticipates it.
Status: calibrating. Per-barrio statistics and the barrio catalogue are already served. The valuation model is being calibrated on the first comparables: POST /valuations validates the request and answers 503 until it is live. We email the keys we have issued.

Authentication

Every request carries your key in the Authorization header. We store only the hash of the key: if you lose it, we issue a new one.

Authorization: Bearer zv_live_9f3c…

Ask for a key at API access. The Explore plan includes 100 requests a month; the other plans, their own quota.

First request

# curl
curl -X POST https://api.zavaluo.com/v1/valuations \
  -H "Authorization: Bearer $ZAVALUO_KEY" \
  -H "Content-Type: application/json" \
  -d '{"address":"Gorriti 4800, Palermo, CABA","kind":"apartment","m2_total":68,"rooms":3,"floor":2}'

// JavaScript (fetch)
const r = await fetch("https://api.zavaluo.com/v1/valuations", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.ZAVALUO_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({ address: "Gorriti 4800, Palermo, CABA", kind: "apartment", m2_total: 68, rooms: 3, floor: 2 })
});
const v = await r.json();

# Python (requests)
r = requests.post("https://api.zavaluo.com/v1/valuations",
    headers={"Authorization": f"Bearer {KEY}"},
    json={"address": "Gorriti 4800, Palermo, CABA", "kind": "apartment", "m2_total": 68, "rooms": 3, "floor": 2})

Create a valuation

POST /v1/valuations

Returns the estimated value for a property. The address alone is enough; each extra attribute narrows the range.

Body

FieldTypeDescription
addressstringAddress with barrio or city. We geocode it and return the precision. Required unless you send lat/lng
lat, lngnumberWGS84 coordinates. If you send them, we ignore address.
countryenumAR (default) · ES
operationenumsale (default) · rent · temporary_rent
kindenumapartment (default) · house · ph · land · office · retail · garage · other
m2_total, m2_coverednumberTotal and covered square metres.
rooms, bedrooms, bathroomsintegerRooms, bedrooms, bathrooms.
floor, year_builtintegerFloor (0 = ground floor) and year built.
parking_spacesintegerParking spaces included.
has_balcony, has_terrace, has_pool, has_elevatorbooleanThe amenities that weigh most in Buenos Aires.
monthly_feesnumberMonthly service charges in local currency.
localestringes-AR (default) · es-ES · en. The language of the explanation.

Response

{
  "id": "7a1e…", "model_version": "ar-caba-sale-2026.09.1", "operation": "sale",
  "estimate_usd": 231000, "low_usd": 212000, "high_usd": 248000,
  "estimate_local": 312000000, "local_currency": "ARS",
  "likely_asking_usd": 244000, "likely_closing_usd": 231000, "asking_vs_closing_adj": -0.053,
  "confidence": 0.86, "comps_count": 23, "comps_radius_m": 500,
  "comps": [ { "listing_id": "…", "distance_m": 120, "price_usd": 239000, "usd_m2": 3414, "m2_total": 70,
             "rooms": 3, "days_on_market": 46, "price_cut_pct": -4.0, "source_url": "https://…" }, … ],
  "calibrating": true,
  "explanation": "Valuado 2% por debajo de la mediana de Palermo por estar en 2º piso al contrafrente…",
  "created_at": "2026-09-12T15:04:11-03:00"
}
The same input with the same model_version returns the same number. Store model_version alongside the result if you may need to audit a valuation later. While calibrating is true, treat the range as the main signal, not the point.

Retrieve a valuation

GET /v1/valuations/{id}

Returns an earlier valuation issued with your key, without recalculating or consuming quota.

Listing index

GET /v1/listings?city=CABA&neighborhood=Palermo&operation=sale&max_price_usd=200000&sort=delta

Every active listing we monitor (portals and direct owners), paginated, with its canonical URL on Zavaluo and, for sales, the USD/m² against the barrio's reference value (delta_vs_reference, null while the barrio is calibrating). The filters are the same as the site's search.

citystringCABA (default).
neighborhoodstringAn official barrio or free text. Without it, the whole city.
operationenumsale (default) · rent · temporary_rent
kindenumapartment · house · ph · …
min_price_usd, max_price_usdnumberPrice range in USD.
min_rooms, min_m2numberMinimum rooms and square metres.
updated_sinceISO 8601Only listings seen after that instant: ideal for syncing hourly.
vibelistTags read from the listing text, comma-separated (luminoso,con_terraza,a_reciclar); returns the listings that have any of them. Each item carries vibe, style, summary_lead and the broken-down surfaces (m2_covered, m2_semi, m2_uncovered).
sortenumrecent (default) · price · delta (best price vs. reference first).
page, page_sizeintegerPage from 1 and size up to 100 (default 50). next carries the URL of the following one.
{ "total": 224, "page": 1, "page_size": 50, "next": "https://api.zavaluo.com/v1/listings?…&page=2", "reference_as_of": "2026-09-18",
  "items": [ { "ref": 1863, "url": "https://www.zavaluo.com/propiedad/belgrano/ZV-1863-ph-3-ambientes-…",
             "title": "PH 3 ambientes con patio y terraza", "price_usd": 200000, "m2_total": 192, "usd_m2": 1042,
             "neighborhood": "Belgrano", "lat": -34.5612, "lng": -58.4587, "rooms": 3,
             "reference_usd_m2": 2815, "delta_vs_reference": -0.63, "entorno_score": 76, "days_on_market": 0, "cover_url": "https://…/01.jpg" }, … ] }

entorno_score (0–100) describes the block from the city government's open data: distance to the subte, incidents reported within 500 m, schools within 800 m, green space and hospitals. It is not a valuation; the detail carries each component and the figure behind it in context. It is null when the listing does not publish the exact address.

predicted_usd_m2, value_delta and deal_score come from the hedonic model in force (model_version in the response): the asking reference for that listing given its surface, rooms, age, parking and surroundings, how much above or below it is asking, and a 0–100 where 50 is “on the model”. A value_delta beyond ±0.45 is almost always a surface or price error at the source, not an opportunity. quality_score (0–100) measures how complete the record is; with sort=delta the index orders by value_delta where it exists.

One listing

GET /v1/listings/{ref}

The full detail by ref (1863 or ZV-1863) or by uuid: description, summary, surfaces, floor, amenities, photos, price history, the structured extraction from the text with its version, and context (surroundings: transport, safety, schools, green space and health scores with the distances and counts behind each). It never includes the publisher's contact details.

Comparables

GET /v1/comparables?lat=-34.5889&lng=-58.4306&kind=apartment&m2_total=70&rooms=3&year_built=1995&parking=true
GET /v1/listings/{ref}/comparables

The most similar active listings around a point (500 m, widening to 1 km and 2.5 km if there are fewer than five), each with its similarity (distance, surface, rooms, bathrooms, age, age of the listing) and its adjusted_usd_m2: the comparable's price adjusted to the property you asked about with the coefficients of the hedonic model in force (model_version). The weighted median of the adjusted figures is the reference, and the range is the p25–p75. confidence A–D sums up count, similarity and dispersion. With asking_usd it returns asking_vs_reference. The variant by ref builds the subject from the listing and excludes it from its own comparables.

It is an asking-price reference, not a valuation: reference.basis says so in every response. The adjustments come from a log-linear model fitted on the active listings of Buenos Aires (surface, rooms, bathrooms, age, parking, direct owner, distance to the subte, safety and green space of the surroundings, type and barrio); drivers carries the adjustments that weighed most, in words.

{ "reference": { "usd_m2": 3180, "low_usd_m2": 2910, "high_usd_m2": 3460, "total_usd": 222600,
                 "confidence": "B", "n_comps": 9, "radius_used_m": 500, "model_usd_m2": 3097, "barrio_median_usd_m2": 3136,
                 "basis": "asking prices of active listings" },
  "comps": [ { "ref": 660, "distance_m": 140, "usd_m2": 2311, "adjusted_usd_m2": 2402, "similarity": 81, "adjustments": { "log_m2": 0.031, "has_parking": 0.145 } }, … ],
  "drivers": [ { "factor": "has_parking", "impact": 0.145, "label": "cochera" } ], "model_version": "hedonic-caba-2026-09-18" }

Barrio index

GET /v1/neighborhoods
GET /v1/neighborhoods/{slug}

Per barrio and per day: active inventory, listings new and withdrawn over 30 days, the share with a price cut, days on market, USD/m² for sale and for monthly rent, gross yield, average surroundings score and the components of the market score (momentum, liquidity, rental, entorno, affordability). market_score is null and calibrating true until there are 30 days of history for momentum and liquidity: we would rather not publish a score that only says “cheap”.

CABA Market Score

GET /v1/market/caba
GET /v1/market/caba/history?from=2020-01&to=2026-08

Monthly context for the city's market: a 0–100 score with five components (transaction activity 30%, mortgage credit 25%, financing conditions 15%, macro stability 15%, sovereign and currency risk 15%), the regime (very_weak … very_strong), the raw metrics behind each (deeds and mortgages from the Colegio de Escribanos, the A3500 dollar, TAMAR/BADLAR, the policy rate, UVA and the BCRA's mortgage stock, INDEC's CPI, country risk), data_quality_score, is_provisional and calculation_version. Each component is a percentile over its own history since 2016.

It is context, not a valuation input: no reference and no comparables range is adjusted with this score (basis repeats that in every response). The historical series is there to chart and to read which market you are selling into. It is recalculated daily and whenever the Colegio publishes a new month.

{ "period": "2026-07", "caba_market_score": 58.4, "regime": "neutral", "score_change_3m": 3.1,
  "components": { "transaction": 61.2, "credit": 71.0, "financing": 44.5, "macro": 66.3, "risk": 40.9 },
  "metrics": { "total_deeds": 6051, "mortgage_share": 0.158, "deeds_yoy_pct": -9.0, "cpi_mom_pct": 2.1, "country_risk": 690, … },
  "data_quality_score": 100, "is_provisional": false, "calculation_version": "caba-market-score-v1" }

Market statistics

GET /v1/market-stats?city=CABA&neighborhood=Palermo&kind=apartment&operation=sale

Per-barrio aggregates, recalculated nightly: median and quartiles of USD/m², active listings, days on market, the median price cut and the asking-to-closing ratio where closings have been reported. Without neighborhood it returns every barrio in the city; the result carries up to 100 rows, most recent first.

{ "stats": [ { "country": "AR", "city": "CABA", "neighborhood": "Palermo", "kind": "apartment", "operation": "sale",
             "as_of": "2026-09-11", "n_active": 4812,
             "p25_usd_m2": 2980, "median_usd_m2": 3410, "p75_usd_m2": 3890,
             "median_days_on_market": 58, "median_price_cut_pct": -4.1, "asking_to_closed_ratio": null } ] }

Barrios

GET /v1/barrios?include=geometry

The 48 barrios of Buenos Aires with slug, name, comuna and centroid, and with include=geometry the city government's official polygon as GeoJSON (WGS84). This is public information: it needs no key and consumes no quota. Use it for maps and to resolve the barrio of a coordinate client-side.

{ "barrios": [ { "slug": "palermo", "name": "Palermo", "comuna": 14, "centroid": { "lng": -58.4245, "lat": -34.5788 } }, … ] }

Confidence and ranges

low_usd and high_usd are the model's 10th and 90th quantiles. confidence (0–1) combines the density of comparables within the radius, the dispersion of their prices and how many real reported closings we have in the area. Where confidence is low the range widens towards the barrio median; we do not invent precision. While the price history is short, calibrating is true.

Asking vs. closing

In Buenos Aires the published price and the deed price differ, and the gap varies by barrio and by point in the cycle. estimate_usd and likely_closing_usd are the likely closing. likely_asking_usd is the asking price that leads to that closing today, and asking_vs_closing_adj the gap applied. The gap is calibrated on closings reported by owners and on public aggregates.

Currencies and exchange rates

The Buenos Aires market trades in USD; every model value is in USD. estimate_local and local_currency convert at the day's MEP rate. We store the oficial, mep and blue series by date, so the conversion is auditable.

Errors

CodeReason
400 Validation failedaddress or lat/lng is missing, or a field has a value out of range. The body includes issues with the field and the detail.
401 Invalid or revoked API keyThe key is missing, invalid or revoked.
404 Not foundThe valuation does not exist, or was not issued with your key.
429 Monthly quota exceededThe key's monthly quota is used up. It resets on the 1st (UTC).
503 CalibratingThe valuation model is not live yet. The statistics and the barrios remain available.

Limits and versions

The quota is monthly per key, and every request consumed counts, including the ones that return 400. The API version is in the URL (/v1); breaking changes ship as /v2 with at least 6 months of overlap. The model is retrained and its model_version changes without affecting the contract; we email and post to the changelog before every major version.

Changelog

2026-09 · /v1 calibrating for Buenos Aires. GET /market-stats and GET /barrios (with the official geometry) are live; POST /valuations validates and answers 503 until the model is calibrated.

API documentation — Zavaluo · Zavaluo