---
title: "Búsqueda de anuncios"
description: "Busca anuncios publicados de Matchai en lenguaje natural con el endpoint /ask (NLWeb). Parámetros, respuesta, alcance por host, límites y ejemplos."
last_updated: "2026-10-21"
lang: "es"
canonical: "https://matchai.co/docs/es/developers/listing-search"
---

# Búsqueda de anuncios

> Busca anuncios publicados de Matchai en lenguaje natural con el endpoint /ask (NLWeb). Parámetros, respuesta, alcance por host, límites y ejemplos.

Source: https://matchai.co/docs/es/developers/listing-search

`/ask` busca anuncios publicados a partir de una frase sencilla, como "3 bedroom condo in Laval under 600k". Sigue el protocolo NLWeb, así que los clientes NLWeb pueden llamarlo sin código personalizado. Es público y de solo lectura, y no necesita cuenta ni clave de API.

```text
https://matchai.co/ask
```

Devuelve los anuncios en el orden en que una persona los querría: primero la mejor coincidencia, según la relevancia para la solicitud y la fecha de la última actualización del anuncio. Ningún corredor puede pagar para cambiar el orden ni para aparecer.

## Buscar en una sola solicitud [#search-in-one-request]

```bash
curl "https://matchai.co/ask?query=3+bedroom+condo+in+Laval+under+600k"
```

Una respuesta abreviada. Esta búsqueda encontró un anuncio, y el `score` es un valor de ejemplo:

```json
{
  "_meta": { "response_type": "answer", "version": "0.55", "mode": "list" },
  "query_id": "6f1d2c1e-3b0a-4a54-9f2e-0c7b8a5d9e41",
  "site": "matchai.co",
  "mode": "list",
  "query": "3 bedroom condo in Laval under 600k",
  "results": [
    {
      "url": "https://alice.matchai.co/bright-condo-montmorency",
      "name": "Bright 3-bedroom condo near Montmorency metro",
      "site": "alice.matchai.co",
      "score": 0.872,
      "description": "$585,000, condo for sale · 3 bedrooms · 1.5 bathrooms · 1,120 sq ft · Montmorency, Laval, Québec · Listed by Alice Tremblay (Agence Exemple)",
      "schema_object": {
        "@context": "https://schema.org",
        "@type": "RealEstateListing",
        "url": "https://alice.matchai.co/bright-condo-montmorency",
        "name": "Bright 3-bedroom condo near Montmorency metro",
        "image": "https://media.example.com/listings/bright-condo-montmorency/cover.jpg",
        "dateModified": "2026-10-12T14:03:22.000Z",
        "offers": {
          "@type": "Offer",
          "price": 585000,
          "priceCurrency": "CAD",
          "availability": "https://schema.org/InStock",
          "businessFunction": "http://purl.org/goodrelations/v1#Sell",
          "url": "https://alice.matchai.co/bright-condo-montmorency",
          "offeredBy": {
            "@type": "RealEstateAgent",
            "name": "Alice Tremblay",
            "worksFor": { "@type": "Organization", "name": "Agence Exemple" }
          }
        },
        "about": {
          "@type": "Apartment",
          "numberOfBedrooms": 3,
          "numberOfBathroomsTotal": 1.5,
          "floorSize": { "@type": "QuantitativeValue", "value": 1120, "unitCode": "FTK" },
          "address": { "@type": "PostalAddress", "addressLocality": "Laval", "addressRegion": "Québec" }
        }
      }
    }
  ]
}
```

Los nombres, las direcciones y el host de las fotos de estos ejemplos son ficticios.

## Solicitud [#request]

Envía la búsqueda como un `GET` con parámetros en la cadena de consulta, o como un `POST` con un cuerpo JSON.

### GET [#get]

<TypeTable
  type={{
    query: { type: 'string', required: true, description: 'La frase de búsqueda. Hasta 500 caracteres; el texto más largo se recorta. Se acepta q como alias.' },
    site: { type: 'string', description: 'Un host de corredor al que limitar la búsqueda, por ejemplo alice.matchai.co o el dominio propio de un corredor. Solo se usa en matchai.co.' },
    query_id: { type: 'string', description: 'Tu propio id para la solicitud: hasta 100 caracteres de A-Z, a-z, 0-9 y . _ : - . Se devuelve sin cambios. Si no envías uno, Matchai lo genera.' },
    mode: { type: '"list"', description: 'Se acepta por compatibilidad con NLWeb. La respuesta siempre es una lista, envíes lo que envíes.' },
    streaming: { type: 'boolean', description: 'Se acepta y se ignora. La respuesta siempre es un único documento JSON.' },
  }}
/>

### POST [#post]

Envía `Content-Type: application/json`. El cuerpo puede tener hasta 16 KB.

```json
{ "query": "4½ à louer sur le Plateau" }
```

La consulta también puede ser un objeto, como en NLWeb:

```json
{ "query": { "text": "condo near the metro in Montréal" }, "prefer": { "mode": "list" } }
```

<TypeTable
  type={{
    query: { type: 'string | { text: string }', required: true, description: 'La frase de búsqueda, con el mismo límite de 500 caracteres. También se acepta un q en el nivel superior.' },
    site: { type: 'string', description: 'Igual que el parámetro de GET.' },
    query_id: { type: 'string', description: 'Igual que el parámetro de GET.' },
    prefer: { type: 'object', description: 'Se acepta por compatibilidad con NLWeb. prefer.mode se ignora, y la respuesta siempre es una lista.' },
  }}
/>

Los parámetros de la cadena de consulta completan todo lo que el cuerpo omita.

### Lo que entiende la consulta [#what-the-query-understands]

La búsqueda lee tu frase con un analizador pequeño y predecible. No llama a un modelo de lenguaje, así que la misma frase siempre produce los mismos filtros. Entiende inglés, francés y español.

| Escribes | Filtra por |
|---|---|
| `under 600k`, `max 750,000`, `moins de 750 000 $`, `hasta 400k` | Un precio máximo |
| `over 300k`, `at least 1.2M`, `plus de 500k`, `desde 200k` | Un precio mínimo |
| `between 400k and 600k`, `entre 400k et 600k` | Un rango de precios |
| `3 bedroom`, `3 br`, `3 chambres`, `3 habitaciones` | Al menos esa cantidad de habitaciones |
| `4½`, `5½` | La notación de Québec para el número de espacios de una vivienda. Un 4½ tiene dos habitaciones, así que `N½` significa al menos N − 2 habitaciones. |
| `2 baths`, `1.5 bathrooms`, `2 sdb` | Al menos esa cantidad de baños |
| `for sale`, `à vendre`, `en venta` | Propiedades en venta |
| `for rent`, `à louer`, `en alquiler` | Alquileres |
| `condo`, `duplex`, `maison`, `chalet`, `terrain`, `townhouse`, `commercial` | Un tipo de propiedad: casa, condominio, apartamento, casa adosada, plex, terreno, cabaña o comercial |

Los montos pueden escribirse como `600k`, `1.2M`, `600 000`, `$750,000` o `2 million`. Un número pequeño sin unidad y sin signo de dólar, como `over 2`, no se interpreta como precio. Si la frase pide venta y alquiler a la vez, o ninguno de los dos, la búsqueda no filtra por ese criterio.

Todo lo demás se convierte en palabra clave. La búsqueda conserva hasta 6 palabras clave, descarta las palabras de menos de 3 letras y las palabras de relleno comunes, e ignora los acentos, así que `montreal` encuentra Montréal. Las palabras clave se comparan con el título, los nombres de lugares, el tipo de propiedad y la descripción. Una coincidencia en un nombre de lugar es la que más cuenta; le siguen el título, el tipo de propiedad y, por último, la descripción.

Las búsquedas devuelven los anuncios disponibles en este momento. Los anuncios vendidos y alquilados no se devuelven.

## Respuesta [#response]

<TypeTable
  type={{
    _meta: { type: 'object', description: 'response_type siempre es answer. version es la versión de NLWeb que sigue la estructura. mode siempre es list.' },
    query_id: { type: 'string', description: 'Tu query_id, o el que generó Matchai.' },
    site: { type: 'string', description: 'El host que respondió, por ejemplo matchai.co.' },
    mode: { type: '"list"', description: 'Siempre list.' },
    query: { type: 'string', description: 'La frase de búsqueda tal como la leyó Matchai, después de quitar los espacios sobrantes y aplicar el límite de 500 caracteres.' },
    results: { type: 'result[]', description: 'Hasta 10 anuncios coincidentes, primero la mejor coincidencia. Un array vacío significa que nada coincidió.' },
  }}
/>

Cada elemento de `results`:

<TypeTable
  type={{
    url: { type: 'string', description: 'La página del anuncio. Es el dominio propio del corredor una vez que ese dominio está activo.' },
    name: { type: 'string', description: 'El título del anuncio.' },
    site: { type: 'string', description: 'El host de la página del anuncio.' },
    score: { type: 'number', description: 'Relevancia y actualidad combinadas, de 0 a 1.' },
    description: { type: 'string', description: 'Una línea con el precio, el tipo, los datos, el lugar y el corredor del anuncio.' },
    schema_object: { type: 'object', description: 'Un RealEstateListing de schema.org con su Offer y la propiedad a la que se refiere. Los valores desconocidos se omiten; nunca se ponen en 0.' },
  }}
/>

Una respuesta exitosa incluye `Link: </llms.txt>; rel="describedby", </openapi.json>; rel="service-desc"`. Para las fotos, los puntos destacados y la descripción completa de un anuncio, usa las [herramientas del servidor MCP](https://matchai.co/docs/es/developers/mcp-server/public-tools) o lee la [copia en Markdown](https://matchai.co/docs/es/developers/agent-readable-pages#markdown-copies-of-pages) del anuncio.

## Qué anuncios se buscan [#which-listings-are-searched]

`/ask` responde para el host al que llamas: si consultas el sitio propio de un corredor, busca en los anuncios de ese corredor, y si consultas `matchai.co`, busca en los de todos.

| Llamas a | Busca en |
|---|---|
| `https://matchai.co/ask` | Todos los anuncios publicados en Matchai. Agrega `site` para limitarla a un corredor. |
| `https://{name}.matchai.co/ask`, un sitio de Matchai | Solo los anuncios publicados en el sitio de ese corredor. |
| `https://{domain}/ask`, el dominio propio de un corredor | Lo mismo, para el sitio que sirve ese dominio. |
| `https://{name}.matchai.pro/ask`, una Página Matchai | La solicitud se redirige a `https://matchai.co/ask`, así que busca en los anuncios de todos los corredores. |

Notas:

- En un sitio de Matchai o en el dominio propio de un corredor, `site` se ignora: el host determina el alcance.
- En `matchai.co`, `site` recibe el host del sitio de un corredor. Un valor que no coincide con ningún sitio publicado se ignora, y la búsqueda abarca a todos. No devuelve una lista vacía.
- Una Página Matchai no tiene búsqueda propia. La redirección es un `307`, que conserva el método y el cuerpo. Para buscar en los anuncios de un profesional, consulta su sitio de Matchai, o llama a `matchai.co` con su sitio como `site`. Desde código de navegador, llama directamente a `matchai.co/ask`, porque un navegador no puede seguir una redirección en una solicitud preflight de origen cruzado.
- Un host sin sitio publicado responde `404`.

## Límites, caché y CORS [#limits-caching-and-cors]

- **Límite de solicitudes:** 60 solicitudes por minuto por cada dirección de origen, sumando `GET` y `POST`. Por encima de ese límite, la respuesta es `429` con `Retry-After: 60`.
- **Resultados:** como máximo 10 por solicitud. No hay paginación, así que acota la frase para llegar a otros anuncios.
- **Caché:** un `GET` sin `query_id` puede almacenarse en caché hasta un minuto (`Cache-Control: public, max-age=60`). Todo lo demás se envía con `no-store`. Un anuncio nuevo aparece en los resultados en aproximadamente un minuto.
- **CORS:** abierto a todos los orígenes para `GET`, `POST` y `OPTIONS`, así que el código de navegador puede llamarlo. `OPTIONS` responde `204`, y las respuestas preflight pueden almacenarse en caché durante 24 horas.

## Errores [#errors]

Los errores son JSON con un código `error` estable y un `message` que puedes mostrarle a una persona.

```json
{ "error": "rate_limited", "message": "Too many requests. Try again in a minute." }
```

| Estado | `error` | Significado y qué hacer |
|---|---|---|
| `400` | `missing_query` | No hay frase de búsqueda. Envía `?query=` o un cuerpo JSON con `query`. |
| `400` | `invalid_json` | El cuerpo del `POST` no es JSON válido. |
| `413` | `too_large` | El cuerpo del `POST` supera los 16 KB. Envía una frase más corta. |
| `404` | `not_found` | El host al que llamaste no tiene anuncios publicados en los que buscar. |
| `429` | `rate_limited` | Demasiadas solicitudes. Espera los segundos que indica `Retry-After`. |
| `503` | `unavailable` | La búsqueda no está disponible temporalmente. Vuelve a intentarlo después de los segundos que indica `Retry-After`. |

Un array `results` vacío es una respuesta exitosa: nada de lo publicado coincidió. Prueba con una zona más amplia, un presupuesto más alto o menos requisitos.

## Más ejemplos [#more-examples]

Busca en los anuncios de un corredor llamando a su sitio. Reemplaza `alice` por el nombre de un sitio real:

```bash
curl "https://alice.matchai.co/ask?query=condo+under+500k"
```

Limita una búsqueda en `matchai.co` a un corredor:

```bash
curl "https://matchai.co/ask?query=house+for+sale&site=alice.matchai.co"
```

Busca desde código con un `POST`:

<Tabs items={['curl', 'JavaScript']}>
<Tab value="curl">

```bash
curl -X POST https://matchai.co/ask \
  -H "Content-Type: application/json" \
  -d '{ "query": "4½ à louer sur le Plateau", "query_id": "rent-plateau-1" }'
```

</Tab>
<Tab value="JavaScript">

```js
const response = await fetch('https://matchai.co/ask', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: '4½ à louer sur le Plateau' }),
});

if (response.status === 429) {
  const wait = Number(response.headers.get('Retry-After') ?? 60);
  throw new Error(`Rate limited. Retry in ${wait} seconds.`);
}

const { results } = await response.json();
for (const listing of results) {
  console.log(`${listing.name} - ${listing.description} - ${listing.url}`);
}
```

</Tab>
</Tabs>

<Cards>
  <Card title="Servidor MCP" href="https://matchai.co/docs/es/developers/mcp-server">
    Dale a un asistente de IA la misma búsqueda, además de consultas de anuncios y de corredores.
  </Card>
  <Card title="Páginas legibles por IA" href="https://matchai.co/docs/es/developers/agent-readable-pages">
    Lee el sitio completo de un corredor en Markdown en lugar de buscar en él.
  </Card>
</Cards>

## Sitemap

- [Todas las páginas de la documentación de Matchai](https://matchai.co/docs/sitemap.md)
- [llms.txt](https://matchai.co/docs/es/llms.txt)
