REST API v1

JSON API to read the Multilistado inventory, manage your listings and receive leads from your site or CRM. Free for verified agents.

Leer en español · Markdown · Updated

Overview

Base URLhttps://multilistado.mx/api/v1
FormatJSON (UTF-8). Send Content-Type: application/json on POST/PUT
AuthenticationAuthorization: Bearer pbm_<prefix>_<secret>
Scopesread (all queries) · write (create, edit, publish, create leads)
Rate limit600 requests per 10 minutes per key
OpenAPI 3.0 description/api/v1/openapi.json · interactive reference

Authentication

  1. Go to Portal → More → API (requires a verified license).
  2. Under Create key type a Label (e.g. "My CRM"), choose Permissions: "Read and write" or "Read only", and click Generate.
  3. Copy the key: it is shown only once. It looks like pbm_ + 8 characters + _ + 48 characters. You can revoke it at any time.

Send it in the Authorization header. For security, keys in the URL are refused (?api_key= returns 401) and the API does not enable CORS: call it from your server, never from your visitors' browsers (the key would be exposed). To show listings on a website without coding, use the widget.

Free for licensed agents and agencies. Create your account, verify your license and generate your API key or widget in minutes.

Create a free account I already have an account

RESO partner keys (partner scope) only work on the RESO Web API; on /api/v1 they get 403.

Minimal client

Store your key in an environment variable (MULTILISTADO_API_KEY) and use this small client in the examples below. Each example continues the previous one.

export MULTILISTADO_API_KEY="pbm_..."   # your key
API=https://multilistado.mx/api/v1
curl -s "$API/me" -H "Authorization: Bearer $MULTILISTADO_API_KEY"

1. Search the MLS

GET /properties returns published listings from the whole Multilistado (plus your own), one page at a time.

curl -s -G "$API/properties" -H "Authorization: Bearer $MULTILISTADO_API_KEY" \
  --data-urlencode "city=Tijuana" --data-urlencode "operation=sale" --data-urlencode "type=house" \
  --data-urlencode "min_price=2000000" --data-urlencode "sort=price_asc" --data-urlencode "limit=10"

Response (trimmed, illustrative):

{
  "pagination": { "page": 1, "pages": 3, "total": 27, "limit": 10 },
  "content": [{
    "id": "07e25392-…", "slug": "casa-en-venta-playas-de-tijuana", "url": "https://multilistado.mx/p/casa-en-venta-playas-de-tijuana",
    "title": "Casa en venta en Playas de Tijuana", "property_type": "house", "status": "published",
    "operations": [{ "type": "sale", "amount": 4350000, "currency": "MXN", "formatted_amount": "$4,350,000 MXN" }],
    "bedrooms": 3, "bathrooms": 2.5, "parking": 2, "construction_m2": 180, "lot_m2": 200,
    "location": { "address": null, "neighborhood": "Playas de Tijuana", "city": "Tijuana", "state": "Baja California", "lat": 32.519, "lng": -117.119, "exact": false },
    "images": [{ "url": "https://…/fachada.jpg", "thumb": "https://…/fachada.jpg" }],
    "agent": { "name": "…", "slug": "…", "phone": "…", "url": "https://multilistado.mx/agente/…" },
    "agency": null, "updated_at": "2026-09-30T14:07:28.671Z", "published_at": "2026-09-30T14:04:19.703Z"
  }]
}

Filters

ParameterDescription
qFree text (Spanish stemming, accent-insensitive)
operationsale (has a sale price) · rental (has a rent price)
typehouse, apartment, land, office, commercial, warehouse, ranch, building, other. Repeat for several: type=house&type=apartment
stateState, exact name: Baja California
city, neighborhoodCity and neighborhood (partial match, accent-insensitive)
min_price, max_pricePrice (sale price with operation=sale, rent with rental, otherwise either). Currencies are not converted
currencyMXN or USD: only listings priced in that currency
min_bedrooms, min_bathrooms, min_parkingMinimums
min_construction, min_lotMinimum built / lot area in m²
featuresMust have all these amenities (Spanish labels from /meta); repeat the parameter
sw_lat, sw_lng, ne_lat, ne_lngMap rectangle (public, approximate coordinates)
lat, lng, radius_kmRadius around a point
updated_sinceISO 8601 time: only changes since then (incremental sync)
sortnewest (default), price_asc, price_desc, updated, relevance (with q). Featured listings come first
page, limitPage (from 1) and size (default 24, max 100)

Included: published listings of verified agents, and yours in any status. Excluded: licensed imports from other MLSs, listings whose owner did not authorize other agents' websites (idx_opt_out) and test accounts.

2. Get one listing

GET /properties/{id} takes the id (UUID) or the slug.

curl -s "$API/properties/casa-en-venta-playas-de-tijuana" -H "Authorization: Bearer $MULTILISTADO_API_KEY"

3. Create a listing

POST /properties (write scope) creates the listing in your inventory as a draft. Required: title (min. 5 characters), city, state and sale_price and/or rent_price.

curl -s -X POST "$API/properties" -H "Authorization: Bearer $MULTILISTADO_API_KEY" -H "Content-Type: application/json" -d '{
  "title": "Casa en venta en Playas de Tijuana", "description": "Casa de 3 recámaras a dos cuadras de la playa.",
  "property_type": "house", "sale_price": 4500000, "sale_currency": "MXN",
  "bedrooms": 3, "bathrooms": 2.5, "parking": 2, "construction_m2": 180, "lot_m2": 200,
  "city": "Tijuana", "state": "Baja California", "neighborhood": "Playas de Tijuana",
  "lat": 32.5201, "lng": -117.1205, "features": ["Vista al mar", "Jardín"], "external_id": "crm-1042"
}'
# Save the "id" from the response:
LISTING_ID="…"

Writable fields: title, description, title_en, description_en, property_type, sale_price, sale_currency, rent_price, rent_currency, rent_period (monthly, weekly, daily, yearly), bedrooms, bathrooms, half_bathrooms, parking, construction_m2, lot_m2, year_built, floors, features, address, neighborhood, city, municipality, state, postal_code, lat, lng, show_exact_address, idx_opt_out, video_url, virtual_tour_url, exclusive, shared_commission, internal_id, images and external_id (your own ID; returned as source_id and unique per agent: if it already exists the API returns 409 conflict with that listing's id so you can PUT instead). Prices accept numbers or text such as "4,500,000". Coordinates are stored exactly but published approximately unless show_exact_address is true. Full detail in the reference.

4. Update

PUT /properties/{id} is partial: send only what changes.

curl -s -X PUT "$API/properties/$LISTING_ID" -H "Authorization: Bearer $MULTILISTADO_API_KEY" -H "Content-Type: application/json" \
  -d '{"sale_price": 4350000, "title_en": "House for sale in Playas de Tijuana"}'

5. Images

POST /properties/{id}/images adds images by public URL (up to 60 per call, in order). The first becomes the cover if there is none. Images are linked, not copied: keep them online (your server, CDN or public http/https storage). API v1 has no binary upload; to upload photos from your computer use the portal. Sending images in a PUT replaces the listing's URL images.

curl -s -X POST "$API/properties/$LISTING_ID/images" -H "Authorization: Bearer $MULTILISTADO_API_KEY" -H "Content-Type: application/json" \
  -d '{"urls": ["https://cdn.your-site.com/photos/1042/front.jpg", "https://cdn.your-site.com/photos/1042/living.jpg"]}'

6. Publish and unpublish

CallNew statusWebhook
POST /properties/{id}/publishpublishedlisting.published
POST /properties/{id}/unpublishdraftlisting.unpublished
DELETE /properties/{id}withdrawn (kept, not deleted)listing.unpublished
curl -s -X POST "$API/properties/$LISTING_ID/publish" -H "Authorization: Bearer $MULTILISTADO_API_KEY"
# {"ok":true,"status":"published"}

Your whole inventory (every status, up to 500, not paginated): GET /my/properties (filter with ?status=draft).

7. Create a lead from your site

POST /leads (write scope) records an inquiry received on your own website or form. The lead is assigned to you; property_id (UUID or slug) is linked only if you manage that listing. You get the usual email notice. name is required.

curl -s -X POST "$API/leads" -H "Authorization: Bearer $MULTILISTADO_API_KEY" -H "Content-Type: application/json" \
  -d "{\"name\": \"Ana López\", \"email\": \"ana@example.com\", \"phone\": \"+52 664 123 4567\", \"message\": \"I am interested in the house.\", \"property_id\": \"$LISTING_ID\", \"source\": \"my-site\"}"

8. Your leads

GET /leads returns your latest 500 leads (from your Multilistado site, the widget, portals and the API), newest first.

curl -s "$API/leads" -H "Authorization: Bearer $MULTILISTADO_API_KEY"

Fields: id, listing_id, listing_title, listing_slug, name, email, phone, message, source (widget:<id>, api, your label…), status, kind (info or tour = showing request), lang, interest, budget_min, budget_max, follow_up_at, tour_at, tour_status, showing_at, id_status (buyer ID: verified/pending), awaiting_id, created_at, updated_at. To get them instantly use webhooks.

Other endpoints

EndpointReturns
GET /meKey owner and scopes
GET /metaProperty types, listing statuses, Mexican states, amenities and currencies (no key needed)
GET /agentsPublic verified agent directory (up to 1000)
GET /agenciesActive agencies (up to 1000)
GET /locationsCities and states with published inventory (top 200)
GET /my/propertiesYour inventory in every status

Pagination

/properties returns pagination: { page, pages, total, limit }. Request the next page with page=2, page=3… up to pages. To sync a large inventory, store the time of your last sync and request only changes with updated_since=2026-09-30T00:00:00Z&sort=updated. /my/properties, /leads, /agents and /agencies are not paginated (fixed caps).

Errors

Errors return JSON with error (a stable code) and usually message:

{ "error": "unauthorized", "message": "Invalid or revoked API key." }
HTTPerrorCause
401unauthorizedMissing, invalid or revoked key, unverified account, or key sent in the URL
403forbiddenKey lacks write, the listing is not yours, or it is a RESO partner key
404not_foundDoes not exist or your key cannot see it
409conflictYou already have a listing with that external_id; the response includes its id
422validationInvalid data; details in errors: [...]
429rate_limitedLimit exceeded; wait the Retry-After seconds
500server_errorOur error: retry later and tell us if it persists

Limits

What the API does not expose