Skip to main content

Upload Your Business Data

Kaleidr can answer questions from your organization's own data — your properties, listings, rooms, rates, opening hours and documents — alongside its baseline knowledge of the world.

Two things are worth stating before anything else, because they shape every decision below.

Your data is served back to your organization only. It is isolated at the database level, not by application logic, and it never reaches an answer on the consumer Kaleidr Map. It is available on your own B2B surfaces and nowhere else.

A language model never writes your data. It reads the header of your export and a handful of sample rows and proposes a column mapping; deterministic code then applies that mapping to every row. A wrong mapping is a correction you make in a form. A model transcribing 500 rows would be 500 chances to invent a price that is later quoted back with a confident timestamp on it, and an invented price is indistinguishable from a real one.

Two ways in

The upload page. Sign in at kaleidr.com and open Vendor Data in your account area, beside Billing and API keys. It walks the same four steps as the API: pick a file, review the proposed mapping, preview what we understood, publish. This is the right route for a spreadsheet.

The API, documented below. Use it when your data already lives in a system that can push, or when you want uploads on a schedule.

Either way you need to be an owner or admin of the organization. This is organization-level data, not per-project — which is why it lives in your account area rather than inside Studio.

Authentication

All calls take a Cognito access token as a bearer, the same one your session already holds:

Authorization: Bearer <access token>

Not a platform API key. Platform keys identify an integration; uploading data is an act of organization administration, so it authenticates as a person with a role. Every path below is under https://api.kaleidr.com.

The shape of an upload

One upload produces one ingest (the job) and one release (the versioned result). A release is draft until it publishes, and publishing supersedes the previous one atomically — readers never see a half-applied update, and there is no window where your organization has no data.

1. Propose a mapping

Send the front of your file — the header row and a few data rows, not the whole export.

MethodPathBodyReturns
POST/inference-api/vendor/mapping/propose{ csv_head }{ mapping_spec, columns, sample_result, notes, errors[] }

csv_head is capped at 16 KB, and the sample is sliced server-side — posting a bigger file does not widen what the model sees.

sample_result is the part to read. The proposed mapping is dry-run over your own sample rows before you ever see it, and sample_result reports what it produced per section. A mapping that reads plausibly and yields nothing is otherwise something you discover only after uploading.

If the proposal cannot be applied you still get 200 with errors populated, not a 5xx. The mapping is editable and fixing one column is the whole interaction, and errors reports everything knowable in one pass — a missing required field and a column name your sheet does not have arrive together rather than one per round trip.

What it catches before you upload: a section missing a field every row needs (stay_date, price_amount, units_available, a place's name or timezone), a {"const": …} timezone that is not a real IANA zone, a currency const that is not three letters, and any object rule that is not a const container. Each of those otherwise fails once per row after the upload.

Limited to 30 proposals per user per hour.

2. Stage a preview

MethodPathBodyReturns
POST/shared-api/vendor-data/ingests{ filename, artifact, source, mapping_spec?, preview?, org_id? }{ ingest_id, release_id, status, status_url, dispatched }
  • filename must end .json or .csv.
  • artifact is the raw file text.
  • source is csv, json or manual.
  • mapping_spec is what step 1 returned, optionally edited. Omit it if you are sending an already-normalized JSON bundle or a places-only CSV.
  • preview: true stages without publishing — strongly recommended for a first upload, and for any change to the mapping.
  • org_id is optional; it defaults to the organization you administer.

Idempotency-Key is required on this call (8–128 characters), and it is scoped per organization. Retrying with the same key returns the existing ingest rather than creating a second one. Use a fresh key when you deliberately re-stage after editing a mapping — that is a genuinely different request, and a key derived from the file would hand you back the ingest built from the old mapping.

3. Watch it

MethodPathReturns
GET/shared-api/vendor-data/ingests/{ingest_id}{ status, attempts, row_counts, error_report, created_at, started_at, finished_at }

status moves pendingrunningsucceeded or failed. On success row_counts carries what we understood — "47 places, 312 rates" — and error_report carries the rows we could not read, with the reason for each.

4. Publish

MethodPathReturns
POST/shared-api/vendor-data/ingests/{ingest_id}/publish{ ingest_id, release_id, status, status_url, dispatched }

Only for an ingest staged with preview: true that has succeeded.

Publishing re-runs the job rather than flipping a flag. It re-reads the same artifact and re-applies the same mapping, so counts and identifiers match by construction — but geocoding is a live call, so a coordinate the provider has since corrected can differ from the one in your preview.

Do not send an Idempotency-Key here. This endpoint does not accept one, and it does not need one: a second publish of the same ingest cannot happen. If your first request timed out on your side but succeeded on ours, the retry returns 409ingest_is_not_a_preview, or publish_already_in_progress if two attempts overlap exactly. Both mean your publish is already under way. Treat them as success, not as an error to retry.

Listing releases

MethodPathReturns
GET/shared-api/vendor-data/releases[{ id, status, published_at, superseded_at, created_at }]

Optionally filtered by ?status=. Exactly one release per organization is published at a time.

Previews expire

A preview you never approve is retired after 14 days, measured from when it finished staging. It is marked superseded rather than deleted, so the upload stays in your history — but it can no longer be published, and you would upload again. Publishing an expired preview returns 409 no_previewed_release_to_publish.

Field notes

timezone is required on every place, and it matters. Rate and availability answers are computed in the property's local calendar — "tonight" at a Sydney hotel is a different day from "tonight" on the server. If your export genuinely has no timezone column, map a constant explicitly:

{ "timezone": { "const": "UTC" } }

Write that deliberately rather than letting it default. UTC is a correct answer for a property that keeps UTC hours and a subtly wrong one for a property that does not, and the wrongness shows up only at the edges of a stay window.

Omitting timezone, or naming a zone that does not exist, is rejected at the propose step rather than after the upload.

Supply coordinates when you have them. A place with lat/lng is used as given — your coordinates are authoritative and we will not re-derive them. A place with only an address is geocoded, and a match we are not confident in is refused rather than guessed: a property placed wrongly on a map is worse than one reported as unresolvable. Half a coordinate is treated as a typo, not a gap.

Re-uploading is cheap and safe. Identifiers are derived from the columns your mapping names as identifying, so the same export produces the same references — re-uploading updates rather than duplicating.

Errors

StatusMeaning
401Missing or expired access token
403Your organization is not enabled for data upload
404No such ingest for your organization
409The ingest is not in a state that allows this call — see the publish notes above
413The file exceeds the upload limit
422The file or mapping could not be read; the body names the rows and reasons
429Rate limited — retry after a pause

What is coming

The API accepts a complete bundle today. Once a mapping is a stored, reusable object it will also accept your own export plus a mapping id, so an integration can post the file it already produces without reshaping it first. A delta API — upsert and delete by natural key, with a since cursor — follows the same route.