Importer vos données métier
Kaleidr peut répondre aux questions à partir des propres données de votre organisation — vos établissements, annonces, chambres, tarifs, horaires d’ouverture et documents — parallèlement à sa connaissance générale du monde.
Deux points méritent d’être précisés avant tout le reste, car ils influencent chaque décision ci-dessous.
Vos données sont renvoyées uniquement à votre organisation. Elles sont isolées au niveau de la base de données, et non par la logique applicative, et elles n’atteignent jamais une réponse sur le Kaleidr Map destiné aux consommateurs. Elles sont disponibles uniquement sur vos propres surfaces B2B.
Un modèle de langage n’écrit jamais vos données. Il lit le header de votre export et quelques sample rows et propose un column mapping ; du code déterministe applique ensuite ce mapping à chaque row. Un mapping incorrect est une correction que vous effectuez dans un formulaire. Demander à un modèle de transcrire 500 lignes créerait 500 occasions d’inventer un prix qui pourrait ensuite être cité avec un timestamp convaincant, et un prix inventé serait impossible à distinguer d’un prix réel.
Disponibilité
L’import de vendor data est une fonctionnalité Enterprise-tier. L’UI d’import et
l’API vérifient toutes deux VENDOR_UPLOAD_TIERS = {"enterprise"} — un owner ou admin Pro-tier
reçoit 403 vendor_data_requires_enterprise pour tout appel d’import.
La vendor-data UI est actuellement désactivée en production (vendorDataEnabled
config flag). Contactez le support Kaleidr si vous êtes
sur Enterprise et souhaitez l’activer pour votre organisation.
De plus, un rôle owner ou admin Enterprise est requis — il s’agit de données au niveau de l’organisation, et non du projet.
Deux méthodes
La page d’import. Connectez-vous sur kaleidr.com et ouvrez
Your Data dans votre espace de compte (chemin nav /vendor-data, à côté de Billing
et API keys). Elle suit les mêmes quatre étapes que l’API : choisir un fichier, vérifier
le mapping proposé, prévisualiser ce qui a été compris, publier. C’est la
bonne approche pour une feuille de calcul.
L’API, documentée ci-dessous. Utilisez-la lorsque vos données existent déjà dans un système capable de push, ou lorsque vous souhaitez planifier les imports.
Authentification
Tous les appels prennent un access token Cognito comme bearer, le même que votre session détient déjà :
Authorization: Bearer <access token>
Pas une platform API key. Les Platform Keys identifient une intégration ; l’import de données
est un acte d’administration de l’organisation, il s’authentifie donc comme une personne disposant
d’un rôle. Tous les chemins ci-dessous se trouvent sous https://api.kaleidr.com.
Structure d’un import
Un import produit un ingest (le job) et un release (le résultat
versionné). Un release reste draft jusqu’à sa publication, et la publication remplace
atomiquement le précédent — les lecteurs ne voient jamais une mise à jour partiellement appliquée et il n’existe
aucune période durant laquelle votre organisation ne possède aucune donnée.
1. Proposer un mapping
Envoyez le début de votre fichier — la ligne d’en-tête et quelques lignes de données, pas la totalité de l’export.
| Method | Path | Body | Returns |
|---|---|---|---|
| POST | /inference-api/vendor/mapping/propose | { csv_head } | { mapping_spec, columns, sample_result, notes, errors[] } |
csv_head est limité à 16 KB et le sample est découpé server-side — envoyer
un fichier plus volumineux n’augmente pas ce que le modèle peut voir.
sample_result est la partie à lire. Le mapping proposé est exécuté en dry-run sur vos
propres sample rows avant même de vous être présenté, et sample_result indique ce qu’il a
produit par section. Sans cela, vous pourriez ne découvrir qu’après l’import qu’un
mapping apparemment plausible ne produit rien.
Si la proposition ne peut pas être appliquée, vous recevez tout de même 200 avec errors renseigné,
pas une erreur 5xx. Le mapping est modifiable et corriger une colonne constitue l’ensemble de
l’interaction. errors rapporte également tout ce qui peut être déterminé en une seule passe — un champ
obligatoire manquant et un nom de colonne absent de votre feuille arrivent ensemble
plutôt qu’un par round trip.
Ce qui est détecté avant l’import : une section à laquelle manque un champ requis par chaque ligne
(stay_date, price_amount, units_available, le name ou
timezone d’un lieu), une timezone {"const": …} qui n’est pas une véritable zone IANA, une currency
const qui ne comporte pas trois lettres et toute règle d’objet qui n’est pas un conteneur const.
Sinon, chacun de ces problèmes échouerait une fois par ligne après l’import.
Limité à 30 propositions par utilisateur et par heure.
2. Préparer une 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 } |
filenamedoit se terminer par.jsonou.csv.artifactest le texte brut du fichier.sourcevautcsv,jsonoumanual.mapping_specest ce que l’étape 1 a renvoyé, éventuellement modifié. Omettez-le si vous envoyez un bundle JSON déjà normalisé ou un CSV contenant uniquement des places.preview: trueprépare sans publier — fortement recommandé pour un premier import et pour toute modification du mapping.org_idest facultatif ; sa valeur par défaut est l’organisation que vous administrez.
Idempotency-Key est requis pour cet appel (8–128 caractères) et son scope
est limité à l’organisation. Réessayer avec la même clé renvoie l’ingest existant
au lieu d’en créer un second. Utilisez une clé nouvelle lorsque vous choisissez volontairement
de re-préparer après avoir modifié un mapping — il s’agit réellement d’une requête différente, et une
clé dérivée du fichier vous renverrait l’ingest construit avec l’ancien mapping.
3. Suivre l’exécution
| Method | Path | Returns |
|---|---|---|
| GET | /shared-api/vendor-data/ingests/{ingest_id} | { status, attempts, row_counts, error_report, created_at, started_at, finished_at } |
status passe de pending → running → succeeded ou failed. En cas de succès,
row_counts indique ce qui a été compris — "47 places, 312 rates" — et
error_report contient les lignes impossibles à lire, avec la raison pour chacune.
4. Publier
| Method | Path | Returns |
|---|---|---|
| POST | /shared-api/vendor-data/ingests/{ingest_id}/publish | { ingest_id, release_id, status, status_url, dispatched } |
Uniquement pour un ingest préparé avec preview: true et terminé avec succès.
La publication réexécute le job au lieu de simplement modifier un flag. Elle relit le même artifact et réapplique le même mapping, de sorte que les counts et identifiers correspondent par construction — mais le geocoding est un appel live, donc une coordinate peut différer si le provider l’a corrigée depuis votre preview.
N’envoyez pas de Idempotency-Key ici. Cet endpoint ne l’accepte pas
et n’en a pas besoin : une seconde publication du même ingest ne peut pas se produire. Si
votre première requête a expiré de votre côté mais a réussi du nôtre, la nouvelle tentative
renvoie 409 — ingest_is_not_a_preview, ou publish_already_in_progress si
deux tentatives se chevauchent exactement. Les deux signifient que votre publication est déjà en cours.
Traitez-les comme un succès, et non comme une erreur à réessayer.
Lister les releases
| Method | Path | Returns |
|---|---|---|
| GET | /shared-api/vendor-data/releases | [{ id, status, published_at, superseded_at, created_at }] |
Filtrage facultatif avec ?status=. Un seul release par organisation est
published à la fois.
Les previews expirent
Une preview que vous n’approuvez jamais est retirée après 14 jours, calculés à partir de la fin
du staging. Elle est marquée superseded plutôt que supprimée, de sorte que l’import
reste dans votre historique — mais elle ne peut plus être publiée et vous devez effectuer un nouvel
import. Publier une preview expirée renvoie 409 no_previewed_release_to_publish.
Notes sur les champs
timezone est requis pour chaque place, et c’est important. Les réponses sur les tarifs et disponibilités
sont calculées selon le calendrier local de l’établissement — "tonight" dans un hôtel à Sydney
correspond à un autre jour que "tonight" sur le server. Si votre export
ne possède réellement aucune colonne timezone, mappez explicitement une constante :
{ "timezone": { "const": "UTC" } }
Faites-le volontairement plutôt que de laisser une valeur par défaut. UTC est une réponse correcte pour un établissement qui fonctionne en horaires UTC, mais subtilement incorrecte pour un établissement qui ne le fait pas ; l’erreur n’apparaît qu’aux limites d’une stay window.
L’absence de timezone, ou le nom d’une zone inexistante, est rejetée dès l’étape
propose plutôt qu’après l’import.
Fournissez les coordinates lorsque vous les avez. Un place possédant lat/lng est utilisé tel
quel — vos coordinates font autorité et nous ne les recalculerons pas. Un
place ne possédant qu’une address est géocodé, et une correspondance dont nous ne sommes pas certains est
refusée plutôt que devinée : placer un établissement au mauvais endroit sur une carte est pire que
de le signaler comme impossible à résoudre. Une demi-coordinate est traitée comme une faute de frappe, pas comme une absence.
Réimporter est peu coûteux et sûr. Les identifiers sont dérivés des colonnes que votre mapping désigne comme identifiantes, de sorte que le même export produit les mêmes références — réimporter met à jour au lieu de dupliquer.
Erreurs
| Status | Meaning |
|---|---|
| 401 | Access token manquant ou expiré |
403 vendor_data_requires_enterprise | L’organisation n’est pas sur Enterprise tier |
| 403 | Votre organisation n’est pas activée pour l’import de données |
| 404 | Aucun ingest correspondant pour votre organisation |
| 409 | L’ingest n’est pas dans un état permettant cet appel — consultez les notes de publication ci-dessus |
| 413 | Le fichier dépasse la limite d’import |
| 422 | Le fichier ou le mapping n’a pas pu être lu ; le body indique les lignes et les raisons |
| 429 | Rate limited — réessayez après une pause |
À venir
L’API accepte aujourd’hui un bundle complet. Une fois qu’un mapping devient un objet stocké et réutilisable,
elle acceptera également votre propre export accompagné d’un mapping id, afin qu’une
intégration puisse envoyer directement le fichier qu’elle produit déjà sans devoir d’abord le remodeler.
Une delta API — upsert et delete par natural key, avec un curseur since — suivra
la même voie.