Published Sep 29, 202611 min read
AI Cities for Tourism Apps: Twelve Cities Already Wired, One Integration, and the Travel Product You Can Ship
Twelve cities are live on AI Cities, each wired across eight systems. Why tourism is the first product surface that maps onto that wiring, the architecture in TypeScript, and four products you can ship this quarter.

By Renato Marinho
Founder · Vinkius
Since AI Cities went live, the question I get has changed shape. It used to be "what is a Connector". It is now "can I build a product on this", and the people asking are not platform people. They run destination marketing organizations, they build trip planners, they operate hotel concierge products, and they all arrive with the same spreadsheet: the list of APIs they would have to integrate to cover a single city properly.
This post answers that with an inventory, an architecture, and the parts that are hard. The short version: tourism is the domain where a wired city maps almost one to one onto a consumer product. A traveler touches six of a city's eight systems in the first seventy two hours, every one of those touches is already a live read, and the integration you would have written for one city is the same integration for twelve.
Why tourism is the first product surface for a wired city
On AI Cities a city is organized into eight systems: mobility, energy, environment, public services, culture, geography, commerce and safety. That is how a city government thinks about itself. It is not how a visitor thinks, and the gap between the two is where a travel product lives.
Take a visitor in Amsterdam for three days. Mobility is the bike dock, the tram, the parking zone they will never find twice. Culture is what is on tonight and whether two tickets still exist. Environment is the rain band arriving at nine and the air by the water. Public services is the address, the monument record, the open dataset behind both. Geography is the distance, the elevation, the route that avoids the hill. Commerce is the price and the card. Safety is the road work that closes the canal route at six.
Six of a city's eight systems, crossed on the first day, without the visitor ever learning the name of a system. No other product category touches a city that broadly that fast.
The second reason is the shape of the workload. Tourism is read heavy and write light. A visitor asks a thousand questions and books a handful of things, which is the ideal workload for a data plane that reads live from source at the moment of the ask and, where a Connector can act, acts on a service rather than on the city. Our own contract on the AI Cities page is explicit: nothing here gives an agent control over public infrastructure. For a travel product that is not a limitation. It is the correct contract.
The third reason is arithmetic. Every travel product I have reviewed carries the same hidden line item: the integrations. One city covered properly means transit, bike share, parking, weather, air quality, events, ticketing, geocoding and the local open data portal, each with its own key, its own rate limit, its own error shape, and its own day when it changes. Multiply that by the cities you want to be in and you have the reason most travel products stop at three markets.
The honest inventory: what is actually wired
Twelve cities are live in beta: Amsterdam, Berlin, Lisbon, London, Madrid, Moscow, New York, Paris, Rio de Janeiro, San Francisco, Singapore and Tokyo. Each is backed by Connectors to its own systems rather than a generic world feed.
Amsterdam is the most complete, so it is the one I will quote precisely: eight systems live today across 40 Connectors. On mobility there is CityBikes for live bike share, TomTom Parking Availability, Google Maps, Mapbox, Uber, and the city's own Parking and Traffic Zones dataset, keyless. On culture there is the Rijksmuseum archive, Eventbrite, Ticketmaster, Bandsintown, and the city's registered events, venues and sport dataset. On environment and safety there is AccuWeather, AirVisual, AQICN, OpenWeather, Open-Meteo, the city's own incident feed for outages and road work, and flood forecasts from the Global Flood Awareness System. On public services there is the DSO open data explorer with more than 122 datasets, the BAG address register, waste and recycling schedules, and the EU open data portal.
Read that list again, because the mix is the point. Roughly half are commercial APIs with an account behind them. Roughly half are the city's own records, reachable without an API key at all. A travel product needs both: the commercial feeds give coverage and quality, the municipal feeds give the facts only a city knows, like which quay is closed or which tree came down in the storm.
Two rules come with that inventory, and I would hold any team to them. The first: the city page states which systems are wired today and which are still being connected, so you commit features against what exists rather than against a roadmap. The second: everything on that page is a live read at the moment you ask. Nothing is pre cached, so your product cannot ship a stale timetable and blame the platform for it.
This is not another travel API
Travel has had APIs for decades. The Amadeus and Duffel world, the GDS lineage, solves inventory: seats, fares, bookings, exchanges. It is excellent at the transaction and it knows nothing about the place. Those APIs can tell you which flight lands at 14:00. They cannot tell you that the road to the hotel closes at six, that the AQI along the corridor is climbing, or that the only gig tonight is three stops away.
The city layer answers that second set of questions, and the two are complements rather than competitors. A product that has the fare but not the street is a booking engine. A product that has the street but not the fare is a guide. The interesting product has both, and until now having both meant owning two integration programs with two different maintenance curves.
That is the actual shift. The transaction APIs were always going to be a commodity you rent. The city side was never available as a commodity at all: you integrated a municipality, or you did not have the data. AI Cities makes the city side rentable in the same way, with the same call pattern, for every city that is wired.
The architecture: one integration, twelve cities
Under the hood every Connector is exposed over MCP, the open protocol the assistants you already use speak. Your application is identified by a pair of keys you create once in the dashboard: a public app id and a secret application key. You address your own travelers by the id you already assign them, and for each of them the SDK hands back a scoped handle to the city systems they connected. Vinkius provisions the connection, holds the credentials, and executes behind a governed data plane. Your code carries no upstream key, no OAuth flow, no per city retry loop.
The unit of scope is the traveler, not the tenant, and this is the design decision I would defend hardest in a travel product. A concierge that can change someone's booking is only safe when the booking it touches belongs to the person asking. Each traveler's Connectors are isolated connections with their own tokens, enumerated and executed inside their own runtime, metered separately and stopped separately. The isolation is enforced by the shape of the data path, not by a policy document.
Here is the loop, straight from the SDK sample, with the traveler's city systems as the tool set:
import OpenAI from 'openai';
import { Vinkius } from '@vinkius/connect';
import { toOpenAITools, runOpenAIToolCall } from '@vinkius/connect/openai';
const openai = new OpenAI();
const MODEL = process.env.OPENAI_MODEL ?? 'your-model-id';
const vinkius = new Vinkius({
appId: process.env.VINKIUS_APP_ID!,
apiKey: process.env.VINKIUS_APP_KEY!,
});
export async function concierge(userId: string, question: string) {
const caps = await vinkius.user(userId).capabilities();
if (caps.length === 0) {
return 'Connect a city first and I can answer that live.';
}
const tools = toOpenAITools(caps);
const messages = [{ role: 'user', content: question }];
for (let step = 0; step < 4; step++) {
const reply = await openai.chat.completions.create({ model: MODEL, messages, tools });
const msg = reply.choices[0]?.message;
if (!msg?.tool_calls?.length) break;
messages.push(msg);
for (const call of msg.tool_calls) {
const result = await runOpenAIToolCall(caps, call, {
idempotencyKey: `${userId}:${call.id}`,
});
const text = result.content.map((c) => c.text).join('\n');
messages.push({
role: 'tool',
tool_call_id: call.id,
content: result.isError ? `The tool reported an error: ${text}` : text,
});
}
}
return reply?.choices[0]?.message?.content ?? '';
}
There is no city specific code in that function. It does not know it is in Amsterdam. The city arrives through the capabilities the traveler has connected, which is why the same function serves twelve cities and the thirteenth without a branch.
Worked example: one question, five systems
"We land at 14:00 with a child and a stroller. Where do we eat tonight near the museum, and how do we get there if it rains?"
Trace what has to happen before that answer is honest:
- Resolve the hotel and the museum to coordinates. Geography: LocationIQ or OpenCage.
- Read the rain band and the air quality for that window. Environment: Open-Meteo and AccuWeather, AQICN for the corridor.
- Read what is on tonight near that address, and whether two tickets exist. Culture: the city events dataset, Eventbrite, Ticketmaster.
- Check the incident feed for the route you were about to recommend. Safety: the city's own status and incidents connector.
- Choose the movement: bikes at the dock, the tram, or parking near the venue. Mobility: CityBikes, TomTom, Google Maps.
Five systems, one conversation, and the traveler never installed anything. Each step is a tool call the model chose, each result is a live read, and every call lands in the audit trail with the traveler id attached. If step four comes back with a closed quay, the answer changes before you send it, not after the guest is standing there.
What is hard, said plainly
Per city variance is real. Amsterdam has eight systems wired across 40 Connectors. Another city on the list may be live on mobility and environment while public services is still being connected. The engineering answer is to enumerate capabilities at runtime and design for a set that changes, not to hardcode a city matrix in your config. The user facing answer is honesty: say what is available, where.
Freshness is the whole promise. A travel product lives or dies on whether the tram is actually running. Reads happen at the moment of the ask, so the failure mode you design for is not stale data, it is the upstream being briefly unavailable. Handle tool level failures as results rather than exceptions, and let the model say plainly that it does not know right now instead of inventing a departure time.
Actions are narrow on purpose. Where a Connector can act, it acts on the service: holding a booking, reserving a spot. It never acts on public infrastructure. Build around reads and a small number of explicit writes and you will never meet the boundary. Design a product that assumes it can retime a city's transit and you have designed something that cannot ship.
Every call is on the record. All of it runs on Vinkius: isolated V8 execution per connection, more than 34 security rules, a signed audit trail of every action, spending limits that pause instead of surprise, and one switch that stops every agent. For a consumer travel product this is the difference between "our AI did something odd last night" and a receipt that names the tool, the traveler and the timestamp. The control plane is covered with source in AI Governance: The Control Plane Behind Every Tool Call Your Agents Make, and the sandbox itself in Zero Cold Starts for Untrusted Code.
Four products you can ship this quarter
A day of trip concierge. Chat first, no download, no login per service. Rain at nine, bikes at the dock by the office, tickets for two before dinner, the last train at 22:50. Every input to that conversation is a live read you already have.
A comfort and accessibility aware router. The itinerary that avoids the hill, the high AQI corridor, the closed quay and the steps at the station. Air quality, elevation, incidents and routing are separate Connectors, composing them is the product, and no incumbent maps app composes them.
A destination back office. For a destination marketing organization or a hotel group: today's events, tonight's venues, the open datasets and the incident feed, feeding a site or a messaging assistant that answers in the visitor's language instead of a static page last updated last spring.
A city layer for an existing travel platform. If you already have the users and the bookings, the leverage is different: one integration, and every city that gets wired becomes a market you can open without shipping a new integration project.
The build starts where the wiring ends
The demo of AI Cities is asking your assistant about a city and getting a live answer. That is not the product. The product is what you build on the same Connectors, for travelers who will never know there was a protocol underneath.
Start at the AI Cities index, open the city you care about, and read which systems are live today. Then wire it with the AI Connect SDK and build the local app that should have existed.
