Consultar datos
Abrir en ChatGPTAbrir en Claudellms.txtllms-full.txtopenapi.json
Contenido
Documentación para desarrolladores
¿Cómo están organizados los datos?
Una clave lee un equipo, un equipo ve colecciones, una colección contiene documentos y cada documento puede tener valores para los campos de esa colección. Un documento es una obra, un contratista o una planta. Una colección agrupa un tipo de ellos.
| Palabra | Lo que es |
|---|---|
| Team | La cuenta de tu empresa en Bidlo. Una clave de API lee un equipo y nada más. |
| Colección | Un tipo de cosa. Por ejemplo, Projects guarda obras, Bid Items guarda precios unitarios tal como se ofertaron, Contractors guarda empresas y Facilities guarda plantas, bancos de material y patios. |
| Documento | Uno de ellos: una obra, una empresa, una planta. |
| Campo | Una cosa que la colección sabe de cada uno de sus documentos, como un nombre, una fecha, una cantidad o un enlace a un documento de otra colección. |
| Value | Lo que guarda un documento en un campo. |
La API llega a cualquier colección que tu equipo vea en la app. Lístalas con collections_list en MCP o https://app.bidlo.ai/api/v1/collections en REST. Una colección se nombra por su id o por su nombre, y los nombres coinciden sin importar mayúsculas. Un nombre que comparten dos colecciones es un 422 que pide el id, y una colección que no existe es un 404.
Algunas colecciones propias de la app, como sus páginas y chats, están cerradas a la API. Una clave también se puede limitar a algunas colecciones al crearla. Cualquiera de los dos casos es un 403.
¿Cómo encuentro los campos de una colección?
Llama a fields_list en MCP, o a la ruta de campos de la colección en REST: cualquiera de las dos devuelve cada campo que tu clave puede leer, con su id, su nombre y su tipo. Primero lista las colecciones y luego pide los campos de una colección.
GET https://app.bidlo.ai/api/v1/collections/<collection id or name>/fields
MCP tool: fields_list, with "collection_id"| Clave | Lo que te dice |
|---|---|
| id | El id del campo, que nunca cambia. |
| name | El nombre que tu equipo le da al campo. |
| field_type | Cómo se guarda el valor, como texto, número, fecha, etiqueta, relación, ubicación o estado. La tabla de operadores de abajo se organiza por ese tipo. |
| primary_key | Si este es el campo del que sale el nombre del documento. |
| reference_id | En una relación, la colección a la que apunta su valor. Es la colección donde se busca un nombre. |
| description | Qué significa el campo. |
Un campo se nombra por su id o su nombre en todo lugar donde una consulta lo pide: en fields, filters, sorts y grouping, en las dos vías. Los nombres coinciden sin importar mayúsculas. Un nombre que comparten dos campos es un 422 que pide el id, y un nombre que no coincide con ningún campo es un 422 que dice Unknown field.
Un equipo puede renombrar un campo integrado, así que el mismo campo se puede llamar de dos formas en dos cuentas. El id nunca cambia. Por eso en esta página no hay ningún id de campo impreso: lee los tuyos en fields_list, y toma cada nombre de campo de los ejemplos de aquí como un ejemplo. Un nombre sirve para una pregunta suelta. El código que tiene que seguir funcionando debe mandar ids.
Un campo que enlaza a una colección que tu clave no puede leer queda fuera de la lista, y fuera de todo resultado.
¿Cómo funcionan los filtros?
Un filtro es un campo, un operador y un valor, cada campo acepta un solo filtro, y el campo se nombra por su id o su nombre en las dos vías. Mándalos como un arreglo; los operadores que acepta un campo dependen de su tipo.
POST https://app.bidlo.ai/api/v1/collections/<collection id or name>/documents/query
MCP tool: documents_query, with "collection_id" added to the same object
{
"filters": [
{
"field_id": "Bid Date",
"operator": "between",
"value": { "start": "2026-10-01", "end": "2026-12-31" },
"conjunction": "AND"
},
{
"field_id": "<field_id of your County field>",
"operator": "contains",
"value": ["<document_id of that county>"]
}
],
"sorts": [{ "field_id": "Bid Date", "direction": "asc" }],
"limit": 100
}En REST, manda la consulta como cuerpo JSON a la ruta de consulta, o como JSON en la cadena de consulta de un GET a la ruta de documentos. En MCP, los mismos parámetros son los argumentos de la herramienta.
Un segundo filtro sobre el mismo campo es un 422 cuyo mensaje dice que combines los dos, como un solo between para un rango de fechas o eq con una lista para opciones.
Cada filtro lleva su propio conjunction, ya sea AND (el predeterminado) o OR, en mayúsculas. Cada filtro OR se une a un grupo, y ese grupo se combina con AND con el grupo AND. No hay anidamiento ni paréntesis.
| Tipo de campo | Operadores | Value |
|---|---|---|
| title, text | eq, ne, contains, not_contains, starts_with, ends_with | Una cadena. eq es exacto y distingue mayúsculas y minúsculas; contains, starts_with y ends_with no las distinguen. |
| number, material | eq, ne, gt, lt, gte, lte, between | Un número, no una cadena; { start, end } para between. |
| date | eq, ne, gt, lt, gte, lte, between, relative_range | Una fecha ISO o una palabra clave; { start, end } para between; { period, timeframe, number } para relative_range. |
| boolean | eq, ne | true o false, no una cadena. eq false incluye valores vacíos; ne false coincide solo con valores true guardados. |
| tag | eq, ne, contains, not_contains | Un arreglo de ids de opciones. Un solo id se lee como un arreglo de un elemento. |
| tags, relation, people | contains, not_contains, eq, ne | Un arreglo de ids de documento, o de ids de usuario para personas. Un id suelto se lee como un arreglo de uno. |
| state | eq, contains, not_contains, ne | Nombres completos de estado, como ["Texas"], nunca la abreviatura. |
| location | within_distance, outside_distance, within_area, outside_area | { lat, lng, radiusInMeters } para distancia; un Polygon o MultiPolygon de GeoJSON como { geometry } para área. |
Todos los tipos también aceptan is_null y is_not_null, sin valor. ne incluye valores vacíos, salvo los booleanos; para tags y people significa “no contiene” ninguno de los ids. Un campo de lista se filtra como tags. Los filtros de fórmula siguen el tipo de resultado, salvo que las fórmulas de ubicación no aceptan operadores de ubicación y en las fórmulas booleanas eq false coincide solo con valores false guardados.
Algunos valores se revisan antes de correr la consulta: un campo de tipo tag, tags, relation, people o state necesita una lista de uno o más ids o nombres, un campo de texto una cadena, y un between un inicio y un fin. Un valor que no pasa la revisión es un 422 que nombra el formato que esperaba, incluida una lista vacía. Los valores de número, fecha, sí o no y ubicación no se revisan antes. Un valor en blanco, como una cadena vacía, un between con un extremo vacío o un área sin un polígono útil, se descarta en vez de aplicarse, así que una consulta que parece sin filtrar casi siempre lo está.
¿Cómo funcionan las fechas?
Un valor de fecha es una cadena de fecha ISO o una palabra clave como today, between acepta un inicio y un fin, y relative_range acepta un periodo, un plazo y un número opcional. Una ventana de licitación es un between; "los próximos tres meses" es un relative_range.
{ "field_id": "Bid Date", "operator": "gte", "value": "2026-10-01" }
{ "field_id": "Bid Date", "operator": "between",
"value": { "start": "2026-10-01", "end": "2026-12-31" } }
{ "field_id": "Bid Date", "operator": "relative_range",
"value": { "period": "next", "timeframe": "month", "number": 3 } }eq en una fecha coincide con todo ese día. Los rangos relativos usan límites del calendario en la zona horaria del equipo.
Cualquiera de today, yesterday, tomorrow, last_week, next_week, last_month, next_month, last_year, next_year puede ir en lugar de una fecha.
relative_range usa tres claves. period es past, next o this; timeframe es day, week, month o year; y number es cuántos de ese plazo past y next retroceden o avanzan, 1 si lo omites. this lo ignora.
¿Cómo filtro por contratista, condado o agencia?
Esos campos enlazan a un documento de otra colección, así que el valor es el id de ese documento; encuentra el id consultando primero esa colección por nombre. El condado de una obra es un documento de una colección de condados, igual que cualquier otro enlace.
1. Find the county, in the collection your County field points at
"collection_id": "<reference_id of your County field>"
"filters": [{ "field_id": "Name", "operator": "eq", "value": "Travis County" }]
2. Filter on its id
"filters": [
{ "field_id": "County", "operator": "contains", "value": ["<document_id of that county>"] }
]El reference_id en fields_list nombra la colección a la que apunta el campo. Consulta esa colección con un filtro sobre su campo de nombre, toma el id del documento que regresa, y llévalo al filtro. Si el nombre coincide con más de un documento, tú eliges cuál querías: la API no adivina.
Un valor de relación es un arreglo de ids, aunque haya uno solo, y un id suelto se lee como un arreglo de uno.
¿Cómo busco cerca de un lugar?
Filtra un campo de ubicación con within_distance y un valor de lat, lng y radiusInMeters, donde el radio va en metros. outside_distance es el mismo filtro al revés.
"filters": [
{
"field_id": "Location",
"operator": "within_distance",
"value": { "lat": 30.2672, "lng": -97.7431, "radiusInMeters": 50000 }
}
]El radio va en metros, así que 50 km son 50000. Las coordenadas de la obra son el centro de la búsqueda cuando buscas quién puede llegar a ella. is_null y is_not_null en el mismo campo son la forma de saber qué documentos traen coordenadas.
Para comprobar si algo está en un área dibujada en vez de usar un radio, usa los operadores de área en la fila de ubicación de la tabla de filtros, con un polígono GeoJSON como valor.
¿Cómo funcionan los órdenes?
Un orden es un campo y una dirección asc o desc, se permiten varios en el orden en que los mandas, y sin ninguno los documentos más nuevos van primero. Un orden nombra su campo igual que un filtro: por id o por nombre.
"sorts": [
{ "field_id": "Bid Date", "direction": "asc" },
{ "field_id": "Name", "direction": "asc" }
]Se aplican en el orden del arreglo, así que el primero es el orden principal. Cada campo acepta un solo orden, y un segundo sobre el mismo campo reemplaza al primero. Ordenar por un campo de ubicación es ordenar por distancia y necesita un punto desde el que medir, que va en el propio orden como location: { "type": "Point", "coordinates": [lng, lat] }.
¿Cómo funcionan las páginas?
Pide un límite de 1 a 500, 100 por defecto, y luego devuelve el next_cursor que trae cada página, con la misma consulta, hasta que regrese null. El límite y el cursor funcionan igual en REST y en MCP.
| Entrada | Lo que hace |
|---|---|
| limit | De 1 a 500, 100 por defecto. |
| cursor | El next_cursor de la página anterior. Mándalo con la misma colección, el mismo límite y los mismos filtros y órdenes. |
| page | Un número de página desde 1, si prefieres contar las páginas tú. |
next_cursor regresa en meta. Es null cuando una página regresa incompleta, y así sabes que terminaste. Una última página llena igual devuelve un cursor, y la página siguiente regresa vacía.
Un cursor mandado con otra colección u otro límite es un 422, y también lo es un cursor mandado con un page. El cursor no lleva tus filtros ni tus órdenes, así que vuelve a mandarlos sin cambios con cada página: una página pedida con otros se responde, no se rechaza. Un límite fuera del rango se rechaza en vez de ajustarse. Ninguna de las dos vías devuelve un conteo total de documentos que coinciden. El cursor cuenta páginas en vez de guardar una posición, así que los documentos que se agregan o cambian mientras lees pueden pasar de una página a otra.
A grouping de un campo y su tipo devuelve grupos en vez de una lista plana: como máximo 500 documentos en total, superar ese número es un 422, y cada grupo contiene solo sus primeros 50 documentos, así que un next_cursor en null ahí no significa que tengas todo. Para leer todos los documentos, consulta sin grouping.
¿Qué devuelve?
Una página de documentos, cada uno con su id, su nombre y los valores guardados por id de campo; la forma de cada valor depende del tipo de campo. REST y MCP responden con el mismo JSON; en MCP es el texto del resultado de la herramienta.
{
"data": [
{
"id": "<document_id>",
"name": "…",
"collection_id": "<collection_id>",
"created_at": "…",
"updated_at": "…",
"fields": {
"<field_id>": {
"value": "2026-10-14",
"field_name": "Bid Date",
"field_type": "date",
"field_id": "<field_id>"
}
}
}
],
"meta": {
"page": 1,
"limit": 100,
"collection_id": "<collection_id>",
"next_cursor": "<cursor>"
}
}fields acepta una lista de ids o nombres de campos y devuelve esos campos, además de los usados para ordenar. Omítelo para solicitar todos los campos legibles. Los valores ausentes pueden dejar claves sin incluir; el campo principal es la propiedad de nivel superior name. Cada valor devuelto incluye el nombre y el tipo de su campo, así que el resultado se puede leer sin otra llamada.
fields también acota la búsqueda de texto libre en query: la búsqueda solo mira los campos que pediste, cualquier campo de orden y el campo de nombre. Omite fields para buscar en todos los campos.
El formato de un valor sigue el tipo del campo.
| Tipo de campo | Value |
|---|---|
| text, number, boolean | Tal como se guarda, leído como JSON donde se puede: un número regresa como número y un sí o no como true o false, y lo mismo pasa con un valor de texto que parece uno, como 123. |
| date | Una cadena de fecha ISO. |
| tag, un relation limitada a un solo documento | Un objeto con un id, un value y un document_id. |
| tags, un relation a varios | Un arreglo de esos objetos. |
| location | Un objeto que puede incluir id, name, address, lat y lng. Si tiene coordenadas, también incluye type: "Point" y coordinates: [lng, lat]. |
| state | El nombre completo del estado como cadena, como "Texas". Un valor guardado como objeto regresa con un id, un name y un abbreviation. |
| people | Ids. |
Un enlace a un documento que tu clave no puede leer se deja fuera del valor en vez de hacer fallar la lectura.
¿Qué pasa cuando una consulta está mal?
Los errores de validación devuelven 422, pero no todos los operadores o valores no admitidos se detectan antes de ejecutar la consulta. Cada uno de estos casos devuelve 422.
- Un parámetro que la consulta no acepta, como team_id: la clave de API ya lleva su equipo.
- Un nombre de campo que no coincide con nada, o un nombre de campo o de colección que coincide con más de uno.
- Dos filtros en un campo, o un valor rechazado por las comprobaciones de forma anteriores.
- En un GET, un fields, filters, sorts, grouping, page y limit que no es JSON válido.
- Un límite fuera de rango, un cursor y una página juntos, o un cursor de otra colección u otro límite.
- Una respuesta agrupada de más de 500 documentos.
Un operador que la tabla no lista para un tipo puede tratarse como igualdad o fallar después. Una colección fuera del alcance de tu clave es un 403, y una que no existe, por id o por nombre, es un 404. En MCP el mismo error regresa como un resultado de herramienta marcado con isError. La REST API lista todos los estados.
## For agents: how to use Bidlo data - Read and write Bidlo data through its MCP server at https://app.bidlo.ai/api/mcp — streamable HTTP, no OAuth. - Get a Bidlo account first: all Bidlo data needs one, https://www.bidlo.ai/developers/access.md says how to get one, and there is no public tier or self-serve signup. - Authenticate with the header `Authorization: Bearer sk_live_...`; the REST API takes the same key, and `me` shows what the key may do. - A team owner or admin mints that key in the app under Settings, then Features, then API, and chooses Read only, Read and write data, or Full access; collection and field changes need `schema:write`. - Read the Bidlo API docs at https://www.bidlo.ai/developers.md, the OpenAPI 3.1 spec for the REST API at https://www.bidlo.ai/openapi.json, and the reference pages: https://www.bidlo.ai/developers/querying.md (filters, operators, dates, places, pages), https://www.bidlo.ai/developers/mcp.md (the tools), https://www.bidlo.ai/developers/rest.md (the routes) and https://www.bidlo.ai/developers/access.md (keys). - Prefer the MCP tools over REST; use `documents_query` with `within_distance` for anything shaped like "near X". - Call `fields_list` before composing a filter — it returns each field’s id, name and type. - Never invent a Bidlo unit price. Read one off the bid items, or say the forecast is not available.