Subir los datos de tu empresa
Kaleidr puede responder preguntas utilizando los datos propios de tu organización — tus propiedades, listados, habitaciones, tarifas, horarios de apertura y documentos — junto con su conocimiento base del mundo.
Hay dos aspectos que conviene dejar claros antes que cualquier otra cosa, porque condicionan cada decisión posterior.
Tus datos solo se sirven de vuelta a tu organización. Están aislados a nivel de base de datos, no mediante lógica de aplicación, y nunca llegan a una respuesta del Kaleidr Map para consumidores. Solo están disponibles en tus propias superficies B2B.
Un modelo de lenguaje nunca escribe tus datos. Lee el header de tu exportación y unas pocas sample rows y propone un column mapping; después, código determinista aplica ese mapping a cada row. Un mapping incorrecto es una corrección que haces en un formulario. Hacer que un modelo transcriba 500 filas supondría 500 oportunidades de inventar un precio que después podría citarse con un timestamp convincente, y un precio inventado sería indistinguible de uno real.
Disponibilidad
La carga de vendor data es una función de Enterprise-tier. Tanto la UI de carga como la
API comprueban VENDOR_UPLOAD_TIERS = {"enterprise"} — un owner o admin de Pro-tier
recibe 403 vendor_data_requires_enterprise en cualquier llamada de carga.
La vendor-data UI está actualmente deshabilitada en production (vendorDataEnabled
config flag). Contacta con soporte de Kaleidr si estás
en Enterprise y necesitas activarla para tu organización.
Además, se requiere un rol de owner o admin de Enterprise — son datos a nivel de organización, no por proyecto.
Dos formas de entrada
La página de carga. Inicia sesión en kaleidr.com y abre
Your Data en el área de tu cuenta (ruta nav /vendor-data, junto a Billing
y API keys). Recorre los mismos cuatro pasos que la API: elegir un archivo, revisar
el mapping propuesto, previsualizar lo que se entendió y publicar. Esta es la
ruta adecuada para una hoja de cálculo.
La API, documentada a continuación. Úsala cuando tus datos ya estén en un sistema que pueda hacer push, o cuando quieras programar cargas periódicas.
Autenticación
Todas las llamadas utilizan un access token de Cognito como bearer, el mismo que tu sesión ya mantiene:
Authorization: Bearer <access token>
No una platform API key. Las platform keys identifican una integración; subir datos
es una acción de administración de la organización, por lo que se autentica como una persona con
un rol. Todas las rutas siguientes están bajo https://api.kaleidr.com.
Estructura de una carga
Una carga produce un ingest (el job) y un release (el resultado
versionado). Un release permanece como draft hasta que se publica, y publicar sustituye
atómicamente al anterior — los lectores nunca ven una actualización aplicada a medias y no hay
ningún intervalo en el que tu organización se quede sin datos.
1. Proponer un mapping
Envía el comienzo de tu archivo — la fila de encabezado y unas pocas filas de datos, no toda la exportación.
| Method | Path | Body | Returns |
|---|---|---|---|
| POST | /inference-api/vendor/mapping/propose | { csv_head } | { mapping_spec, columns, sample_result, notes, errors[] } |
csv_head está limitado a 16 KB y el sample se recorta server-side — enviar
un archivo mayor no amplía lo que ve el modelo.
sample_result es la parte que debes leer. El mapping propuesto se prueba mediante dry-run sobre tus
propias sample rows antes incluso de mostrártelo, y sample_result informa de lo que
produjo por sección. Un mapping que parece plausible pero no produce nada
sería algo que, de otro modo, quizá descubrirías solo después de subirlo.
Si la propuesta no puede aplicarse, sigues recibiendo 200 con errors rellenado,
no un 5xx. El mapping es editable y corregir una columna constituye toda la
interacción. errors además informa de todo lo que puede conocerse en una pasada — un campo
obligatorio ausente y un nombre de columna que tu hoja no contiene llegan juntos
en lugar de uno por cada round trip.
Qué detecta antes de subir: una sección a la que le falta un campo necesario en todas las filas
(stay_date, price_amount, units_available, el name o
timezone de un lugar), una timezone {"const": …} que no sea una zona IANA real, una currency
const que no tenga tres letras y cualquier regla de objeto que no sea un contenedor const.
De lo contrario, cada uno de estos casos fallaría una vez por fila después de la carga.
Limitado a 30 propuestas por usuario y hora.
2. Preparar una preview
| Method | Path | Body | Returns |
|---|---|---|---|
| POST | /shared-api/vendor-data/ingests | { filename, artifact, source, mapping_spec?, preview?, org_id? } | { ingest_id, release_id, status, status_url, dispatched } |
filenamedebe terminar en.jsono.csv.artifactes el texto bruto del archivo.sourceescsv,jsonomanual.mapping_speces lo devuelto por el paso 1, opcionalmente editado. Omítelo si envías un bundle JSON ya normalizado o un CSV solo de places.preview: trueprepara sin publicar — muy recomendable para una primera carga y para cualquier modificación del mapping.org_ides opcional; de forma predeterminada se usa la organización que administras.
Idempotency-Key es obligatorio en esta llamada (8–128 caracteres), y está
limitado por organización. Reintentar con la misma clave devuelve el ingest existente
en lugar de crear uno nuevo. Utiliza una clave nueva cuando deliberadamente
vuelvas a preparar los datos después de editar un mapping — es una solicitud realmente distinta, y una
clave derivada del archivo te devolvería el ingest creado con el mapping anterior.
3. Supervisarlo
| Method | Path | Returns |
|---|---|---|
| GET | /shared-api/vendor-data/ingests/{ingest_id} | { status, attempts, row_counts, error_report, created_at, started_at, finished_at } |
status pasa de pending → running → succeeded o failed. Si tiene éxito,
row_counts indica lo que se entendió — "47 places, 312 rates" — y
error_report contiene las filas que no pudieron leerse, junto con el motivo de cada una.
4. Publicar
| Method | Path | Returns |
|---|---|---|
| POST | /shared-api/vendor-data/ingests/{ingest_id}/publish | { ingest_id, release_id, status, status_url, dispatched } |
Solo para un ingest preparado con preview: true que haya terminado correctamente.
Publicar vuelve a ejecutar el job en lugar de simplemente cambiar un flag. Vuelve a leer el mismo artifact y aplica de nuevo el mismo mapping, por lo que counts e identifiers coinciden por construcción — pero geocoding es una llamada live, por lo que una coordinate puede diferir si el provider la ha corregido desde tu preview.
No envíes un Idempotency-Key aquí. Este endpoint no lo acepta,
y no lo necesita: no puede producirse una segunda publicación del mismo ingest. Si
tu primera solicitud agotó el tiempo de espera de tu lado pero tuvo éxito en el nuestro, el reintento
devuelve 409 — ingest_is_not_a_preview, o publish_already_in_progress si
dos intentos se solapan exactamente. Ambos significan que la publicación ya está en curso.
Trátalos como éxito, no como un error que deba reintentarse.
Listar releases
| Method | Path | Returns |
|---|---|---|
| GET | /shared-api/vendor-data/releases | [{ id, status, published_at, superseded_at, created_at }] |
Opcionalmente filtrado por ?status=. Exactamente un release por organización está
published en cada momento.
Las previews caducan
Una preview que nunca apruebas se retira después de 14 días, medidos desde que
terminó su staging. Se marca como superseded en lugar de eliminarse, por lo que la carga
permanece en tu historial — pero ya no puede publicarse y tendrías que volver a
subirla. Publicar una preview caducada devuelve 409 no_previewed_release_to_publish.
Notas sobre campos
timezone es obligatorio para cada place y es importante. Las respuestas sobre tarifas y disponibilidad
se calculan utilizando el calendario local de la propiedad — "tonight" en un hotel de Sydney
es un día diferente de "tonight" en el server. Si tu exportación realmente
no contiene una columna timezone, mapea explícitamente una constante:
{ "timezone": { "const": "UTC" } }
Hazlo deliberadamente en lugar de dejarlo como default. UTC es una respuesta correcta para una propiedad que opera con horas UTC y sutilmente incorrecta para una que no lo hace; el error solo aparece en los límites de una stay window.
Omitir timezone o indicar una zona inexistente se rechaza ya en el paso
propose, no después de la carga.
Proporciona coordinates cuando las tengas. Un place con lat/lng se utiliza tal
cual — tus coordinates son autoritativas y no volveremos a derivarlas. Un
place que solo tenga una address se geocodifica, y una coincidencia en la que no confiemos se
rechaza en lugar de adivinarse: colocar una propiedad incorrectamente en un mapa es peor que
informar que no puede resolverse. Media coordinate se trata como un error tipográfico, no como un dato ausente.
Volver a subir es barato y seguro. Los identifiers se derivan de las columnas que tu mapping define como identificadoras, por lo que la misma exportación genera las mismas referencias — volver a subir actualiza en lugar de duplicar.
Errores
| Status | Meaning |
|---|---|
| 401 | Access token ausente o caducado |
403 vendor_data_requires_enterprise | La organización no está en Enterprise tier |
| 403 | Tu organización no está habilitada para carga de datos |
| 404 | No existe ese ingest para tu organización |
| 409 | El ingest no se encuentra en un estado que permita esta llamada — consulta las notas de publicación anteriores |
| 413 | El archivo supera el límite de carga |
| 422 | No se pudo leer el archivo o mapping; el body indica las filas y los motivos |
| 429 | Rate limited — vuelve a intentarlo después de una pausa |
Próximamente
Actualmente la API acepta un bundle completo. Cuando un mapping se convierta en un objeto almacenado y reutilizable,
también aceptará tu propia exportación más un mapping id, de modo que una
integración pueda enviar directamente el archivo que ya produce sin remodelarlo primero.
Una delta API — upsert y delete por natural key, con cursor since — seguirá
la misma ruta.