API reference

Build with TravelMindsAI in 60 seconds.

One auth header, JSON in, JSON out. Below: quick-start in four languages, then the endpoint reference. Prefer interactive? Open the API explorer — Swagger UI over the live OpenAPI 3.1 spec (68 endpoints, dark-themed, "Try it out" against production). Raw spec at /openapi.json or api.travelminds.ai/openapi.json for codegen / Stoplight / Postman.

Open the API explorer → Download spec (JSON)

Authentication

Sign up to receive an API key starting with tmai_live_. Send it as a Bearer token. Each key is rate-limited per the plan attached to your account; the limit is enforced at /v1/me and on every data endpoint.

Authorization: Bearer tmai_live_xxxxxxxxxxxxxxxxxxxxxxxx

Quick start: list UNESCO World Heritage sites

curl 'https://api.travelminds.ai/v1/unesco?limit=10' \
  -H 'Authorization: Bearer tmai_live_xxxxxxxxxxxxxxxxxxxxxxxx' \
  -H 'Accept: application/json'
import os, httpx

API_KEY = os.environ["TMAI_API_KEY"]

r = httpx.get(
    "https://api.travelminds.ai/v1/unesco",
    params={"limit": 10},
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=30,
)
r.raise_for_status()
for site in r.json():
    print(site["site_name"], "—", site["country_name"], site.get("year_inscribed"))
const fetch = require("node-fetch");

const url = new URL("https://api.travelminds.ai/v1/unesco");
url.searchParams.set("limit", "10");

const r = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.TMAI_API_KEY}` },
});
if (!r.ok) throw new Error(`status ${r.status}`);
const sites = await r.json();
for (const s of sites) console.log(s.site_name, "—", s.country_name, s.year_inscribed);
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type Site struct {
    SiteName      string `json:"site_name"`
    CountryName   string `json:"country_name"`
    YearInscribed int    `json:"year_inscribed"`
}

func main() {
    req, _ := http.NewRequest("GET",
        "https://api.travelminds.ai/v1/unesco?limit=10", nil)
    req.Header.Set("Authorization", "Bearer "+os.Getenv("TMAI_API_KEY"))

    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()

    var ss []Site
    json.NewDecoder(resp.Body).Decode(&ss)
    for _, s := range ss { fmt.Println(s.SiteName, "—", s.CountryName, s.YearInscribed) }
}

Endpoints

Full schema at openapi.json. Highlights:

Core (global)

GET/v1/cities — list with iso2 / population / score filters.
GET/v1/pois — POIs filtered by city, source, quality class.
GET/v1/pois/{id}/nearby — nearest points of interest to an anchor POI (proximity index, sub-200ms).
GET/v1/hotels, /v1/restaurants, /v1/experiences — lodging and activity rows.
GET/v1/visa — passport × destination visa rules.
GET/v1/scores/{city_id} — composite destination score with sub-dimensions.
GET/v1/narratives/{city_id} — generated city narratives, hallucination-checked.
GET/v1/unesco — UNESCO World Heritage sites.
GET/v1/cities/{id}/context — country-enriched context bundle (state, district, circuits, heritage, transit).
GET/v1/cities/{id}/similar — cities most like a given destination, by learned similarity embedding (~135K-city coverage).
GET/v1/snapshots — quarterly Parquet bundle (Growth tier+).
GET/v1/me — current account, plan, this-month usage, quota remaining.

India-specific (more countries on the roadmap)

GET/v1/states/in — 36 Indian states & UTs with capital, region, area, population.
GET/v1/circuits — canonical Indian tourism circuits.
GET/v1/circuits/{slug} — circuit detail with sequenced stops.
GET/v1/heritage/in — ASI Centrally Protected Monuments.

Rate limits

Per-minute and per-month quotas are scoped to your plan. The headers X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset are included on every response. /v1/me returns the canonical monthly counter.

Errors

Standard HTTP semantics: 401 bad key, 403 revoked key, 429 rate-limit hit (with Retry-After), 404 resource not found, 422 validation failure with a Pydantic detail body.

Status

Live status at status.travelminds.ai. Probes run every 2 minutes. We post incidents within 15 minutes of detection.