REST API
Abrir en ChatGPTAbrir en Claudellms.txtllms-full.txtopenapi.json
Contenido
¿Qué cubre la REST API?
La API REST lee y escribe los documentos de cualquier colección que tu equipo pueda ver, en https://app.bidlo.ai/api/v1. Cada ruta de abajo parte de https://app.bidlo.ai. Las lecturas requieren una clave que pueda leer datos; las escrituras requieren una que pueda editar datos o colecciones y campos, como indica la tabla.
| Método | Ruta | Lo que hace | Permiso |
|---|---|---|---|
| GET | /api | Muestra qué puede hacer esta clave: sus permisos, su límite de colecciones y su vencimiento. | Read data |
| GET | /api | Lista las colecciones que esta clave puede leer. | Read data |
| POST | /api | Crea una colección para tu equipo. | Editar colecciones y campos |
| GET | /api | Lee una colección, por id o por nombre. | Read data |
| PATCH | /api | Renombra una colección o cambia su descripción o ícono. | Editar colecciones y campos |
| DELETE | /api | Elimina una colección de tu equipo u oculta una colección pública para tu equipo. | Editar colecciones y campos |
| GET | /api | Lista los campos de una colección: id, nombre y tipo. | Read data |
| POST | /api | Agrega un campo, una fórmula o una relación. | Editar colecciones y campos |
| GET | /api | Lee una página de documentos: filtros, órdenes, un límite y un cursor. | Read data |
| POST | /api | Agrega un documento, o hasta 500 a la vez. | Edit data |
| PATCH | /api | Cambia campos de hasta 500 documentos de una colección. | Edit data |
| POST | /api | La misma lectura, con la consulta como un solo objeto JSON. | Read data |
| GET | /api | Lee un documento por id. | Read data |
| PATCH | /api | Cambia campos de un documento. | Edit data |
| DELETE | /api | Manda un documento a la papelera. | Edit data |
| PUT | /api | Reemplaza los documentos a los que apunta un campo de relación. | Edit data |
| POST | /api | Saca un documento de la papelera. | Edit data |
| POST | /api | Busca las filas por uno a tres campos, actualiza las coincidencias y agrega el resto. Puede correr primero como prueba. | Edit data |
| GET | /api | Lee la nota de un documento como Markdown. | Read data |
| PUT | /api | Reemplaza la nota de un documento, y se niega si alguien la guardó desde que la leíste. | Edit data |
| POST | /api | Agrega texto al final de una nota. | Edit data |
| PATCH | /api | Renombra un campo o cambia sus ajustes o fórmula. | Editar colecciones y campos |
| DELETE | /api | Elimina un campo; los campos primarios y del sistema se conservan. | Editar colecciones y campos |
| GET | /api | Lista las opciones de un campo de etiqueta. | Read data |
| POST | /api | Agrega una opción de etiqueta, con un color opcional. | Editar colecciones y campos |
| POST | /api | Devuelve un token y una URL firmados para cargar un archivo. | Edit data |
| POST | /api | Verifica una carga, crea el archivo y lo pone en cola para procesarlo. | Edit data |
| GET | /api | Lee detalles del archivo y una URL de descarga válida por 15 minutos. | Read data |
| DELETE | /api | Envía un archivo del equipo a la papelera. | Edit data |
| GET | /api | Lee los comentarios de un documento. | Read data |
| POST | /api | Agrega un comentario como la persona dueña de la clave. | Edit data |
| PATCH | /api | Edita un comentario de la persona dueña de la clave. | Edit data |
| DELETE | /api | Elimina un comentario de la persona dueña de la clave. | Edit data |
| GET | /api | Lee el historial de campos de un documento. | Read data |
{collection} y {field} aceptan un id o un nombre, y {document_id} siempre es un id; Consultar datos explica cómo se comparan los nombres. Ninguna clave tiene acceso a las colecciones internas de la app (páginas, chats, flujos, vistas y similares), y los webhooks y los ajustes del equipo no tienen ruta.
/openapi.json es toda la API como especificación OpenAPI 3.1; la app ofrece la suya en https://app.bidlo.ai/api/v1/openapi.json, sin necesidad de clave.
¿Cómo me autentico?
Manda tu clave de API como token bearer en el encabezado Authorization; la clave lleva tu equipo, así que ninguna solicitud manda un team_id. La misma clave funciona en el servidor MCP.
Authorization: Bearer YOUR_API_KEYUna clave empieza con sk_live_. Acceso y claves explica cómo conseguir una, qué puede hacer y cómo revisarla con GET /me.
¿Cómo hago una solicitud?
Un GET lleva su entrada en la cadena de consulta y cualquier otro método lleva un cuerpo JSON, y los dos rechazan un parámetro que no conocen. Un team_id, o cualquier otro parámetro que la operación no acepta, es un 422.
En un GET, fields, filters, sorts, grouping, page, limit son texto JSON, codificado en la URL dentro de la cadena de consulta. Uno que no se pueda leer es un 422 que dice Invalid filters (o el que haya sido), no una respuesta completa sin aviso. Una consulta larga se escribe más fácil como POST …/documents/query, que acepta la misma entrada como cuerpo JSON.
Gana la ruta. Un cuerpo que repite un valor de la ruta con otro distinto es un 422 que dice Conflicting collection_id.
Una respuesta lleva el encabezado X-Request-Id en cuanto empieza la operación. Un error anterior a eso (una ruta desconocida, un método equivocado, un JSON que no se puede leer, un valor de ruta en conflicto) lleva su request_id solo en el cuerpo. Cítalo cuando escribas a soporte.
¿Cómo filtro, ordeno y pagino?
Los filtros y los órdenes nombran un campo por id o por nombre, y paginas con un límite de hasta 500 y el cursor que devuelve cada página llena. Consultar datos detalla los operadores, el valor que acepta cada tipo de campo, los órdenes, la paginación y la agrupación.
| Parámetro | Tipo | Predeterminado | Lo que hace |
|---|---|---|---|
| fields | array of field ids or names | every field | Qué campos regresan. Los campos por los que ordenas también pueden regresar. |
| filters | array | none | Qué documentos regresan. Hasta 100. |
| sorts | array | newest first | El orden en que regresan. Hasta 100. |
| grouping | object | none | Pide la respuesta en grupos en vez de una sola lista plana. |
| query | string | none | Texto libre, que se busca en los campos que pides y en el título. |
| limit | number | 100 | Filas por página. De 1 a 500. |
| page | number | 1 | Qué página, contando desde 1. |
| cursor | string | none | Dónde terminó la última página: su meta.next_cursor. |
curl -X POST https://app.bidlo.ai/api/v1/collections/<collection>/documents/query \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": [
{
"field_id": "Bid Date",
"operator": "between",
"value": { "start": "2026-10-01", "end": "2026-12-31" }
}
],
"sorts": [{ "field_id": "Bid Date", "direction": "asc" }],
"limit": 100
}'curl --get https://app.bidlo.ai/api/v1/collections/<collection>/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode 'filters=[{"field_id":"Bid Date","operator":"between","value":{"start":"2026-10-01","end":"2026-12-31"}}]' \
--data-urlencode 'sorts=[{"field_id":"Bid Date","direction":"asc"}]' \
--data-urlencode "limit=100"¿Cómo se ve una respuesta?
Cada operación exitosa devuelve su resultado en data, con la paginación en meta cuando devuelve una página. GET /documents/{document_id} devuelve un documento con la misma forma, en data.
{
"data": [
{
"id": "<document_id>",
"name": "<the value of the collection's primary field>",
"collection_id": "<collection_id>",
"created_at": "<iso timestamp>",
"updated_at": "<iso timestamp>",
"fields": {
"<field_id>": {
"value": "<shaped by field_type>",
"field_name": "Bid Date",
"field_type": "date",
"field_id": "<field_id>",
"field_value_id": "<field_value_id>"
}
}
}
],
"meta": {
"page": 1,
"limit": 100,
"collection_id": "<collection_id>",
"next_cursor": "<a string, or null on the last page>"
}
}field_name es el nombre que tu equipo le dio al campo, y field_id no cambia cuando cambia el nombre. Lo que está en value sigue el tipo de campo; Consultar datos muestra cada formato.
¿Cómo agrego y cambio documentos?
Con una clave que pueda editar datos, haz POST de documentos a una colección para agregarlos, PATCH a un documento para cambiarlo, y upsert para comparar filas con lo que ya existe. Las escrituras cambian los documentos de tu equipo en Bidlo, igual que una edición en la app hecha por la persona que creó la clave.
Crear
documents es un objeto { name, fields } o un arreglo de hasta 500. name es el título. Bidlo crea los ids. data contiene un documento completo para una entrada, o un arreglo para un lote. Su id es el id del documento, con el mismo formato que una lectura de documento. El valor predeterminado de un campo no se llena en un documento creado mediante la API.
curl -X POST https://app.bidlo.ai/api/v1/collections/<collection>/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: <a new unique string for each write>" \
-d '{
"documents": [
{
"name": "<title>",
"fields": {
"Bid Date": "2026-11-12",
"County": ["<document_id>"]
}
}
]
}'Actualizar
PATCH /documents/{document_id} acepta fields y cambia solo los campos que mandas.
curl -X PATCH https://app.bidlo.ai/api/v1/documents/<document_id> \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "fields": { "Bid Date": "2026-11-19" } }'Actualización masiva
PATCH /collections/{collection}/documents acepta hasta 500 filas { document_id, fields } de esa colección y responde con data.updated_count.
curl -X PATCH https://app.bidlo.ai/api/v1/collections/<collection>/documents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"documents": [
{ "document_id": "<document_id>", "fields": { "<field_id>": "<new value>" } },
{ "document_id": "<document_id>", "fields": { "<field_id>": "<new value>" } }
]
}'Upsert
match_fields nombra de uno a tres campos que juntos identifican un documento. Cada una de las hasta 500 filas en rows que coincide con un documento lo actualiza, y cada una que no coincide con ninguno se agrega. update_mode es overwrite por defecto, o fill_empty para llenar solo los campos vacíos. En data, la respuesta cuenta lo que se creó y actualizó, y un arreglo errors nombra cualquier fila que coincidió con más de un documento (ambiguous_match), y esa fila se omite.
Usa campos distintos de tipo title, text, number, date, state o tag, o relaciones directas de un solo destino. La comparación recorta y agrupa espacios, ignora mayúsculas y minúsculas y estandariza fechas. Las etiquetas y relaciones coinciden por nombre, no por id. Una clave de coincidencia totalmente vacía nunca coincide.
Un documento público coincidente con un nombre distinto se omite con public_document_rename, incluso con fill_empty; actualiza su campo principal por separado. Envía cada clave de coincidencia una sola vez por lote.
Upsert también acepta etiquetas para tags y relaciones. Resuelve las etiquetas existentes y crea los documentos referenciados que falten en una ejecución real; una prueba no crea ninguno.
dry_run: true reporta lo que pasaría y no escribe nada. Córrelo primero en una importación grande.
curl -X POST https://app.bidlo.ai/api/v1/collections/<collection>/documents/upsert \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"match_fields": ["Name", "Bid Date"],
"rows": [
{ "name": "<title>", "fields": { "Bid Date": "2026-11-12", "Status": "<document_id>" } }
],
"update_mode": "fill_empty",
"dry_run": true
}'Relaciones
PUT /documents/{document_id}/relations/{field} reemplaza todos los documentos a los que apunta un campo de relación con target_document_ids, hasta 500. Un arreglo vacío la deja en blanco. Una relación que acepta un solo documento rechaza más.
curl -X PUT https://app.bidlo.ai/api/v1/documents/<document_id>/relations/<field_id> \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "target_document_ids": ["<document_id>", "<document_id>"] }'Papelera y restauración
DELETE manda un documento a la papelera; no se borra nada. POST …/restore trae de vuelta la entrada más reciente de la papelera que puedes ver, o responde 404 que dice Document is not in your trash.
curl -X DELETE https://app.bidlo.ai/api/v1/documents/<document_id> \
-H "Authorization: Bearer YOUR_API_KEY"
curl -X POST https://app.bidlo.ai/api/v1/documents/<document_id>/restore \
-H "Authorization: Bearer YOUR_API_KEY"Notes
La nota de un documento se lee como Markdown con GET …/note. PUT …/note la reemplaza y acepta base_updated_at: el data.updated_at de tu última lectura, o null para un documento sin nota. Si alguien guardó la nota desde entonces, la respuesta es un 409 conflict; vuelve a leerla y rehaz el cambio. POST …/note/append no necesita un token del cliente. Comprueba las ediciones simultáneas hasta tres veces y aun así puede devolver 409 conflict. Recorta los espacios del texto añadido y lo separa del contenido existente con dos saltos de línea. Una nota que incluye una vista no se puede cambiar mediante la API.
curl -X PUT https://app.bidlo.ai/api/v1/documents/<document_id>/note \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"markdown": "<the whole note, as Markdown>",
"base_updated_at": "<updated_at from your last read, or null>"
}'¿Cómo cambio colecciones y campos?
Editar colecciones y campos permite que una clave cree, renombre y elimine colecciones y campos, incluidas fórmulas, relaciones y opciones de etiquetas. El permiso es schema:write. Elige Acceso completo o agrega este permiso en Personalizado; Leer y escribir datos no lo incluye.
Colecciones
POST /collections acepta un nombre y, opcionalmente, una descripción y un ícono. PATCH /collections/{collection_id} cambia esos detalles. DELETE /collections/{collection_id} elimina una colección del equipo u oculta una colección pública para tu equipo. El valor de data.status es deleted o soft_deleted. Al eliminar una colección propia se eliminan sus documentos y valores, las páginas dependientes y los campos del equipo que la referencian. Una clave limitada a ciertas colecciones no puede crear una colección.
Campos y fórmulas
POST /collections/{collection_id}/fields acepta name y type. Los tipos son text, number, tag, tags, relation, date, people, boolean, location, state, formula. PATCH /fields/{field_id} cambia un nombre, los ajustes, una fórmula o los ajustes de una relación. El tipo de un campo existente no puede cambiar. DELETE /fields/{field_id} elimina un campo; los campos primarios y del sistema no se pueden eliminar.
Las fórmulas usan ids de campos entre llaves, nunca nombres de campos. Los valores relacionados usan el id de un campo de relación seguido del id del campo de destino. La clave debe poder leer todas las dependencias.
POST /collections/<collection>/fields
{
"name": "Bid Total",
"type": "formula",
"formula": "{<field id>} * 2",
"settings": { "decimal_places": 2 }
}{<relation field id>}.{<target field id>}Una relación necesita reference_collection_id. Su objeto opcional relation acepta enable_two_way y reverse_field_name. Los campos vinculados deben pertenecer a tu equipo para cambiar el vínculo. Los destinos y los campos vinculados deben estar dentro del acceso de la clave.
settings acepta solo los ajustes indicados en la solicitud de OpenAPI. No acepta propiedades internas del campo ni tipos de resultado controlados por el servidor. Las fórmulas o los ajustes inválidos devuelven 422 validation.
Opciones de etiquetas
GET /fields/{field_id}/options lista opciones con Leer datos. POST /fields/{field_id}/options agrega una con Editar colecciones y campos. Envía name y, opcionalmente, color: un nombre válido de la paleta o un color hexadecimal, solo en una colección de opciones de color. En otro caso, el color devuelve un 422. Renombra o elimina una opción mediante las rutas de documentos, usando su id de documento.
Un campo de etiqueta puede crear su propia colección oculta de opciones. Una clave limitada a ciertas colecciones debe indicar una colección de opciones existente y permitida en reference_collection_id.
¿Cómo cargo un archivo?
Pide a la API las instrucciones de carga, envía los bytes con PUT directamente a la URL firmada de almacenamiento y finaliza la carga mediante la API. Cargar y finalizar requieren Editar datos. El límite por archivo es 250 MiB (262,144,000 bytes); el cuerpo de una solicitud a la API tiene un límite de 4.5 MB, por eso los bytes van directamente al almacenamiento.
POST /files/uploads
{
"filename": "plans.pdf",
"content_type": "application/pdf",
"size_bytes": 1024
}{
"data": {
"upload_id": "<signed upload token>",
"url": "<presigned S3 URL>",
"method": "PUT",
"headers": {
"Content-Type": "application/pdf",
"Content-Length": "1024",
"If-None-Match": "*"
},
"expires_at": "<ISO timestamp>"
}
}El ejemplo declara un PDF de 1024 bytes; envía el tamaño y el tipo de contenido reales de tu archivo. Las instrucciones de carga vencen a los 15 minutos. Copia todos los encabezados recibidos al PUT, incluidos Content-Length y If-None-Match. Envía solo los bytes del archivo a la URL recibida.
curl -X PUT '<data.url>' \
-H 'Content-Type: application/pdf' \
-H 'Content-Length: 1024' \
-H 'If-None-Match: *' \
--data-binary @plans.pdfPOST /files
{
"upload_id": "<data.upload_id>",
"attach_to": { "document_id": "<document>", "field_id": "<field>" }
}Finalizar verifica el tamaño y el tipo de contenido cargados, crea el archivo y lo pone en cola para procesarlo si el tipo es compatible. Reutilizar un valor válido de upload_id devuelve el mismo archivo activo. attach_to es opcional y reemplaza el valor del campo de destino; no lo agrega al final. El campo debe permitir escritura y apuntar a Files. Una clave limitada debe permitir Files y la colección donde se adjunta.
{
"data": {
"id": "<file>",
"name": "plans.pdf",
"filename": "plans.pdf",
"content_type": "application/pdf",
"size_bytes": 1024,
"download_url": "<signed download URL>",
"download_expires_at": "<ISO timestamp>"
}
}GET /files/{file_id} necesita Leer datos y devuelve una URL de descarga válida por 15 minutos. Solo los archivos activos del equipo que estén en su almacenamiento se pueden descargar así. DELETE /files/{file_id} necesita Editar datos y envía el archivo a la papelera. Las escrituras genéricas de documentos en Files siguen bloqueadas.
503 upload_signing_unavailable significa que la firma de cargas no está configurada en el servidor. Un token de carga inválido o vencido, o bytes que no coinciden con el tamaño o tipo declarados, devuelven 422 validation.
¿Cómo leo comentarios e historial?
Lee los comentarios o el historial de campos de un documento con su id, un límite y el cursor de la página anterior. Ambas lecturas requieren Leer datos. El parámetro limit tiene un valor predeterminado de 100 y acepta de 1 a 500. Los resultados están en data; envía meta.next_cursor de vuelta como cursor hasta que sea null.
Comments
GET /documents/{document_id}/comments lista comentarios. POST /documents/{document_id}/comments crea uno. Envía el comentario como texto en body. PATCH /comments/{comment_id} edita ese texto; DELETE /comments/{comment_id} elimina el comentario. Las escrituras requieren Editar datos. La persona dueña de la clave es la autora, y la clave solo puede editar o eliminar los comentarios de esa persona.
POST /documents/<document>/comments
{ "body": "<comment text>" }{
"data": [{
"id": "<comment>",
"user_id": "<user>",
"author": null,
"body": "<comment text>",
"parent_id": null,
"created_at": "<ISO timestamp>",
"updated_at": null
}],
"meta": { "next_cursor": null }
}Historial de campos
GET /documents/{document_id}/history devuelve los cambios de campos que la clave puede leer. old_value puede ser null cuando la app no lo guardó. Se omiten los campos y valores vinculados fuera del acceso de la clave. Una página puede estar vacía y aun tener un cursor siguiente; sigue consultando hasta que el cursor sea null.
GET /documents/<document>/history?limit=100&cursor=<next cursor>Los elementos van del más reciente al más antiguo según created_at, luego id. Cada uno incluye id, created_at, action_type, field_id, new_value, old_value, source_url, user, field y meta.
field incluye id, name y type. user es null o incluye id, first_name, last_name y avatar; los últimos tres pueden ser null. source_url puede ser null; meta siempre es null.
¿Qué valor acepta cada campo?
Escribe cada valor en su forma simple: el texto como cadena, un número como número, una fecha en ISO 8601, y una etiqueta, varias etiquetas o una relación como ids de documento. En una creación o un upsert, el título va en name, nunca en fields. En una actualización, el título es un campo como cualquier otro: manda el id o el nombre del campo principal dentro de fields.
| Tipo de campo | Escríbelo como |
|---|---|
| text, title | Una cadena |
| number | Un número |
| boolean | true o false |
| date | Una fecha o marca de tiempo ISO 8601 |
| tag | Un id de documento |
| tags, relation | Un arreglo de ids de documento |
| people | Un arreglo de ids de usuario |
| location | Un Point, LineString o Polygon de GeoJSON. Las líneas y los polígonos se guardan como un Point representativo; su geometría no se conserva. |
| state | El nombre o el código del estado |
Omitir un campo lo deja sin cambios. Envía null o una cadena vacía para vaciar un campo escalar; envía una selección vacía para quitar tags o people, y [] para vaciar una relación.
Los campos de fórmula, rollup y lookup son de solo lectura, igual que un campo que agregó una integración y que mantiene de solo lectura. Un campo existente al que se conectó una integración sigue siendo editable. Escribir un campo de solo lectura es un 422 que nombra el campo. Lo mismo pasa al mandar el mismo campo dos veces en una fila. Un id de documento que no existe, está en la papelera o está en una colección que tu equipo no puede ver es un 404 que lista esos ids en details. Uno en una colección fuera del límite de la clave, o en una que la API no abre, es un 403.
¿Una escritura masiva es todo o nada?
No: cada fila se revisa antes de escribir nada, pero la escritura no es una sola transacción, así que una falla a medio camino puede dejar escritas las filas anteriores. La mayoría de los errores en un lote se atrapan en esa primera revisión, y no se escribe nada.
Cuando un lote sí falla a medio camino, lee antes de volver a escribir: consulta los documentos que mandaste, o vuelve a correr el lote como upsert, que actualiza lo que ya está en vez de agregarlo dos veces. Un Idempotency-Key no cubre esto: repite una respuesta que se guardó, y una solicitud que falló a medio camino no guardó ninguna, así que un reintento simple vuelve a escribir.
¿Qué errores puedo recibir?
Todo error es JSON con un objeto error que lleva un código y un mensaje, y un request_id para citar a soporte. Algunos errores agregan details: el campo, los ids o el parámetro que falló.
{
"error": {
"code": "validation",
"message": "Unknown field",
"details": { "field": "<the field you sent>" }
},
"request_id": "<request_id>"
}| Status | Code | Cuándo |
|---|---|---|
| 401 | unauthorized | Sin clave, una clave que no es válida, o una clave cuyo creador salió del equipo. |
| 401 | key_expired | La clave pasó su fecha de vencimiento. |
| 403 | subscription_expired | La suscripción del equipo venció. |
| 403 | forbidden_scope | A la clave le falta el permiso, la colección está fuera del límite de la clave, o la colección es una que la API no abre. |
| 403 | forbidden_role | La clave tiene el permiso, pero el rol de su creador ya no lo permite. |
| 404 | not_found | No existe esa ruta, colección o documento. Un 404 de documento lista los ids en details. |
| 405 | method_not_allowed | La ruta existe, pero no con ese método. El encabezado Allow lista los que acepta. |
| 409 | conflict | Alguien guardó la nota después de que la leíste. |
| 409 | idempotency_in_progress | La primera solicitud con este Idempotency-Key sigue corriendo. |
| 409 | idempotency_unrecorded | La escritura se hizo, pero su respuesta no se pudo guardar. Lee antes de reintentar. |
| 422 | validation | La entrada no cuadra: un parámetro desconocido, un valor equivocado, un campo desconocido o ambiguo, un campo de solo lectura, un cursor inválido. |
| 422 | idempotency_mismatch | El Idempotency-Key ya se usó para otra solicitud. |
| 429 | rate_limited | Por encima de las lecturas o escrituras del minuto. Retry-After dice cuántos segundos esperar. |
| 500 | internal_error | La llamada falló del lado de Bidlo. |
| 503 | upload_signing_unavailable | La firma para cargar archivos no está configurada en el servidor. |
| 503 | unavailable | No se pudo llegar a algo de lo que depende la llamada. Vuelve a intentar en un rato. |
El encabezado X-Request-Id de la respuesta, cuando viene, coincide con request_id. Decide según code, no según message: el mensaje está escrito para personas y puede cambiar de redacción.
¿Cuántas llamadas puedo hacer?
Cada clave tiene 600 lecturas y 120 escrituras por minuto de reloj, y una llamada que supera ese límite es un 429 con un encabezado Retry-After. Dos claves no comparten un conteo.
Una respuesta que cuenta para el límite lleva X-RateLimit-Limit y X-RateLimit-Remaining. Si pasas el límite, espera los Retry-After segundos, que llegan hasta el inicio del siguiente minuto. Servidor MCP explica el límite de llamadas a herramientas.
¿Cómo reintento una escritura sin riesgo?
Manda un encabezado Idempotency-Key con la escritura, y un reintento con la misma clave y la misma solicitud recibe la primera respuesta durante 24 horas, siempre que esa respuesta se haya guardado. Funciona con cualquier método menos GET.
Idempotency-Key: <a new unique string for each write>La clave tiene de 1 a 200 caracteres, y es nueva para cada escritura. La misma clave con una solicitud distinta es un 422 idempotency_mismatch, y un reintento mientras la primera sigue en curso es un 409 idempotency_in_progress. Una solicitud que falló no se guarda, así que un reintento vuelve a ejecutarla; una que nunca terminó queda libre después de diez minutos.
¿Y las rutas de colección anteriores?
Las rutas anteriores de projects, contractors y facilities siguen respondiendo con su contrato anterior, pero el código nuevo debe usar las rutas de documentos de colecciones. Son /api/v1/projects, /api/v1/contractors y /api/v1/facilities, y sources es un alias obsoleto de facilities. Cada solicitud debe enviar un team_id, limit llega hasta 2000 con page pero no cursor, y la mayoría de los errores regresan como { "error": "<message>" }.
## 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.