Portal Inmobiliario APIportalinmobiliario.com ↗
Access property listings from portalinmobiliario.com. Search by type, operation, and location. Retrieve price in UF/CLP, rooms, bathrooms, area m², and address.
What is the Portal Inmobiliario API?
The Portal Inmobiliario API provides 2 endpoints for accessing property listing data from Chile's largest real estate platform. Use search_listings to query apartments, houses, offices, land, and commercial properties across sale and rental operations, returning up to 48 results per page with price, rooms, bathrooms, area in m², and location. Use get_listing_detail to pull the full attribute set for any individual listing by its MLC ID or URL.
curl -X GET 'https://api.parse.bot/scraper/f3817e67-e705-4258-a9a6-8fa44f79e1e1/search_listings?location=santiago-metropolitana&operation=venta&property_type=departamento' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace portalinmobiliario-com-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""
Portal Inmobiliario API Client
A Python client for scraping property listings from Portal Inmobiliario (Chile's leading real estate platform).
Get your API key from: https://parse.bot/settings
"""
import os
import requests
from typing import Optional, Dict, List, Any
class ParseClient:
"""Client for the Portal Inmobiliario Parse API."""
def __init__(self, api_key: Optional[str] = None):
"""
Initialize the Parse API client.
Args:
api_key: Optional API key. If not provided, uses PARSE_API_KEY environment variable.
"""
self.base_url = "https://api.parse.bot"
self.scraper_id = "f3817e67-e705-4258-a9a6-8fa44f79e1e1"
self.api_key = api_key or os.getenv("PARSE_API_KEY")
if not self.api_key:
raise ValueError("API key must be provided or set in PARSE_API_KEY environment variable")
def _call(self, endpoint: str, method: str = "POST", **params) -> Dict[str, Any]:
"""
Make an API call to the Parse Bot service.
Args:
endpoint: The endpoint name to call
method: HTTP method (GET or POST)
**params: Query or body parameters
Returns:
Response JSON as dictionary
Raises:
requests.RequestException: If the API call fails
"""
url = f"{self.base_url}/scraper/{self.scraper_id}/{endpoint}"
headers = {
"X-API-Key": self.api_key,
"Content-Type": "application/json"
}
if method == "GET":
response = requests.get(url, headers=headers, params=params)
elif method == "POST":
response = requests.post(url, headers=headers, json=params)
else:
raise ValueError(f"Unsupported HTTP method: {method}")
response.raise_for_status()
return response.json()
def search_listings(
self,
property_type: str = "departamento",
operation: str = "venta",
location: str = "vitacura-metropolitana",
page: int = 1
) -> Dict[str, Any]:
"""
Search property listings by type, operation, and location.
Args:
property_type: Property type slug (e.g., departamento, casa, oficina, terreno, local-comercial)
operation: Operation type: venta (sale) or arriendo (rent)
location: Location slug (e.g., vitacura-metropolitana, santiago-metropolitana)
page: Page number (1-based). Each page returns up to 48 listings.
Returns:
Dictionary containing total count, current page, listings count, and listings array
"""
return self._call(
"search_listings",
method="GET",
property_type=property_type,
operation=operation,
location=location,
page=page
)
def get_listing_detail(
self,
listing_url: Optional[str] = None,
listing_id: Optional[str] = None
) -> Dict[str, Any]:
"""
Get detailed information for a specific property listing.
Args:
listing_url: Full URL of the listing (from search results)
listing_id: MLC listing ID (e.g., MLC-1742229599)
Returns:
Dictionary containing detailed listing information
Raises:
ValueError: If neither listing_url nor listing_id is provided
"""
if not listing_url and not listing_id:
raise ValueError("Either listing_url or listing_id must be provided")
params = {}
if listing_url:
params["listing_url"] = listing_url
if listing_id:
params["listing_id"] = listing_id
return self._call("get_listing_detail", method="GET", **params)
def format_listing_summary(listing: Dict[str, Any]) -> str:
"""Format a listing for display."""
price_display = f"{listing.get('price_prefix', '')} {listing['price']}".strip()
return (
f" {listing['title']}\n"
f" Price: {price_display} {listing['currency']}\n"
f" Rooms: {listing['rooms']} | Bathrooms: {listing['bathrooms']}\n"
f" Area: {listing['area_m2']} m² ({listing['area_type']})\n"
f" Location: {listing['location']}\n"
f" ID: {listing['id']}\n"
)
def format_listing_detail(detail: Dict[str, Any]) -> str:
"""Format detailed listing information for display."""
price_display = f"{detail.get('price_prefix', '')} {detail['price']}".strip()
output = (
f"Title: {detail['title']}\n"
f"ID: {detail['id']}\n"
f"Price: {price_display} {detail['currency']}\n"
f"Rooms: {detail['rooms']}\n"
f"Bathrooms: {detail['bathrooms']}\n"
f"Area: {detail['area_m2']} m²\n"
f"Location: {detail['location']}\n"
)
if detail.get('attributes'):
output += "\nAdditional Attributes:\n"
for attr_name, attr_value in detail['attributes'].items():
output += f" {attr_name}: {attr_value}\n"
return output
if __name__ == "__main__":
# Initialize the client
client = ParseClient()
print("=" * 80)
print("Portal Inmobiliario Property Market Analysis")
print("=" * 80)
# WORKFLOW: Search apartments for sale, analyze top listings, get details
print("\n[STEP 1] Searching for apartments (departamentos) for sale in Vitacura...")
search_results = client.search_listings(
property_type="departamento",
operation="venta",
location="vitacura-metropolitana",
page=1
)
total_listings = search_results['data']['total']
listings = search_results['data']['listings']
print(f"✓ Found {total_listings} total listings in Vitacura")
print(f"✓ Showing {len(listings)} listings on page 1\n")
# Display summary of first 5 listings
print("[STEP 2] Top 5 listings summary:\n")
top_listings = listings[:5]
for i, listing in enumerate(top_listings, 1):
print(f"{i}. {format_listing_summary(listing)}")
# Get detailed information for top 3 listings
print("\n" + "=" * 80)
print("[STEP 3] Fetching detailed information for top 3 listings...")
print("=" * 80)
detailed_listings = []
for i, listing in enumerate(top_listings[:3], 1):
listing_id = listing['id']
print(f"\n[{i}/3] Fetching details for: {listing['title']}...")
try:
detail = client.get_listing_detail(listing_id=listing_id)
detailed_listings.append(detail['data'])
print(f"✓ Details retrieved successfully\n")
print(format_listing_detail(detail['data']))
except Exception as e:
print(f"✗ Error fetching details: {e}\n")
# Price comparison analysis
print("\n" + "=" * 80)
print("[STEP 4] Price Comparison Analysis")
print("=" * 80)
uf_prices = []
clp_prices = []
for detail in detailed_listings:
if detail['currency'] == 'UF':
uf_prices.append(detail['price'])
else:
clp_prices.append(detail['price'])
if uf_prices:
avg_uf = sum(uf_prices) / len(uf_prices)
print(f"\nAverage price (UF): {avg_uf:,.2f}")
print(f"Price range (UF): {min(uf_prices):,.2f} - {max(uf_prices):,.2f}")
if clp_prices:
avg_clp = sum(clp_prices) / len(clp_prices)
print(f"\nAverage price (CLP): {avg_clp:,.2f}")
print(f"Price range (CLP): {min(clp_prices):,.2f} - {max(clp_prices):,.2f}")
# WORKFLOW: Search rental market in a different location
print("\n" + "=" * 80)
print("[STEP 5] Searching rental market in Las Condes...")
print("=" * 80)
rental_results = client.search_listings(
property_type="casa",
operation="arriendo",
location="las-condes-metropolitana",
page=1
)
rental_listings = rental_results['data']['listings']
print(f"✓ Found {rental_results['data']['total']} total rental listings")
print(f"✓ Showing {len(rental_listings)} listings on page 1\n")
if rental_listings:
print("First 3 rental houses available:\n")
for i, listing in enumerate(rental_listings[:3], 1):
print(f"{i}. {format_listing_summary(listing)}")
# Get details for a rental property
if rental_listings:
first_rental = rental_listings[0]
print("\n" + "=" * 80)
print(f"[STEP 6] Detailed view of: {first_rental['title']}")
print("=" * 80 + "\n")
try:
rental_detail = client.get_listing_detail(listing_id=first_rental['id'])
print(format_listing_detail(rental_detail['data']))
except Exception as e:
print(f"Error fetching rental details: {e}")
print("\n" + "=" * 80)
print("Analysis complete!")
print("=" * 80)Search property listings by type, operation, and location. Returns up to 48 listings per page with price, rooms, bathrooms, area, and location information.
| Param | Type | Description |
|---|---|---|
| page | integer | Page number (1-based). Each page returns up to 48 listings. |
| location | string | Location slug (e.g., vitacura-metropolitana, santiago-metropolitana, las-condes-metropolitana, providencia-metropolitana) |
| operation | string | Operation type: venta (sale) or arriendo (rent) |
| property_type | string | Property type slug: departamento, casa, oficina, terreno, local-comercial |
{
"type": "object",
"fields": {
"page": "integer - current page number",
"total": "integer - total number of listings matching the search",
"listings": "array of listing objects with title, url, id, currency, price, rooms, bathrooms, area_m2, area_type, location, and optional price_prefix",
"listings_count": "integer - number of listings returned on this page"
},
"sample": {
"data": {
"page": 1,
"total": 3299,
"listings": [
{
"id": "MLC-1863859893",
"url": "https://portalinmobiliario.com/MLC-1863859893-parque-costanera-residences-_JM",
"price": 7990,
"rooms": "1 a 3",
"title": "Parque Costanera Residences",
"area_m2": "46 - 149",
"currency": "UF",
"location": "Américo Vespucio Nte. 2920, Vitacura, Parque Bicentenario, Vitacura",
"area_type": "útiles",
"bathrooms": "1 a 4"
}
],
"listings_count": 48
},
"status": "success"
}
}About the Portal Inmobiliario API
Search Listings
The search_listings endpoint accepts four optional filters: operation (venta or arriendo), property_type (slugs include departamento, casa, oficina, terreno, local-comercial), location (slugs such as vitacura-metropolitana or las-condes-metropolitana), and page for 1-based pagination. Each response includes a total count of matched listings alongside a listings array. Each listing object carries id, title, url, price, currency (UF or CLP $), rooms, bathrooms, area_m2, area_type, and location. Project listings may also include a price_prefix field such as "Desde".
Listing Detail
The get_listing_detail endpoint accepts either a listing_url taken from search results or a listing_id in MLC format (e.g., MLC-1234567890). The response returns the same core fields — id, title, price, currency, rooms, bathrooms, area_m2, location — plus an attributes object containing all specification table fields for that listing, which can include surface details, floor number, parking, and other property-specific metadata that does not appear in search result objects.
Currency and Pricing
Chilean real estate is priced in both UF (Unidad de Fomento, a inflation-indexed unit) and CLP (Chilean pesos). The currency field identifies which unit applies to a given price value. Project listings that represent a range of units often set price_prefix to "Desde" to indicate a starting price. Both rooms and bathrooms can return a string representing either a single value or a range, reflecting multi-unit project listings.
The Portal Inmobiliario API is a managed, monitored endpoint for portalinmobiliario.com — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when portalinmobiliario.com changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official portalinmobiliario.com API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Aggregate sale and rental prices by neighborhood using the
locationfilter to track UF/m² trends across Santiago communes. - Build a property comparison tool that fetches full
attributesobjects viaget_listing_detailfor user-selected listings. - Monitor new listings for a specific
property_typeandoperationcombination by pollingsearch_listingsand comparing against a stored listingidset. - Populate a CRM with lead properties by ingesting
title,url,price, andlocationfrom paginated search results. - Analyze room-to-price ratios for
departamentolistings inprovidencia-metropolitanausingrooms,area_m2, andpricefields. - Compile a dataset of commercial properties (
local-comercial,oficina) available forarriendoto support business location research. - Validate listing data by cross-referencing
search_listingsresults with the fullattributesobject returned byget_listing_detail.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Portal Inmobiliario have an official developer API?+
What does `get_listing_detail` return that `search_listings` does not?+
attributes object, which contains the full specification table for a listing. This can include fields like parking count, floor number, property condition, and other metadata specific to the listing type. The search_listings endpoint returns only the core fields common to all listings.Does the API cover regions outside Santiago?+
location parameter accepts slugs that correspond to locations across Chile, not just Santiago. However, listing density is significantly higher for Santiago communes. Coverage for other regions depends on what is published on the platform at query time.Does the API return contact details or agent information for listings?+
How does pagination work in `search_listings`?+
total field in the response indicates the full count of matching results. Increment the page parameter (1-based) to walk through subsequent pages. If listings_count is less than 48, you have reached the last page of results.