Retailer Agent
The Retailer Agent is an AI agent that helps travellers find trips and explore alternatives through a natural-language interface — chat or voice. It guides the user through the whole journey: destination and station discovery, connection search, fare and offer comparison, vacancy and seat checks, cart and checkout-link generation, carrier terms and conditions, and post-sales support for existing bookings.
The agent is exposed as a plain HTTP + WebSocket API, so it can be embedded in your own chat UI, voice channel, contact-centre tooling, or back-office application. Distribusion also ships a ready-made chat widget on top of it.
Please note that this is an enterprise API feature. Reach out to your Partnership Manager for more information about unlocking this and other advanced features. We are actively developing the Retailer Agent, and we are aware that bugs may occur occasionally. If an error persists, please contact us.
Base URL
All endpoints are served under the /agent prefix:
Host | Use for |
| Standard requests. |
| Long-running requests — streaming chat and voice WebSockets. This host allows a 600 s request timeout; the standard host does not. |
Authentication
The Retailer Agent endpoints expect an API key in the headers:
POST https://api.distribusion.com/agent/chat
api-key: <your-agent-api-key>
Content-Type: application/json
Accept: application/json
This key is specific to the Retailer Agent and the MCP Server, and is not your regular Retailer API key — see API Authentication. Contact your Partnership Manager to get access to your Retailer Agent API key.
The key identifies your retailer account, so no retailer code has to be passed in the request. The Retailer API key that the agent uses to reach Distribusion's booking services is resolved server-side and is never exposed to the client.
Voice WebSockets cannot carry custom headers. There, the same key is sent as api_key inside the first JSON message on the socket (see Voice below).
Conversation Model
Every chat request carries two identifiers (user ID and conversation ID) that you choose and keep stable, as well as the user's message text:
Field | Meaning |
| Stable identifier for the end user. Conversations, history and personalisation are scoped to it. |
| Identifier for one conversation thread. Reuse it to continue a conversation; generate a new one to start fresh. |
| The user's message. |
Conversation state is stored server-side, so you do not have to replay the transcript on each turn. Use the /history and /conversations endpoints to re-populate a UI after a page refresh or a checkout round-trip.
Endpoints
Travel agent (main chat)
Method & path | Purpose |
| Run one turn and return the complete reply in a single JSON response. |
| The primary conversational endpoint. Streams the run as newline-delimited JSON ( |
| Cancel an in-flight stream for a conversation (stop-generation). |
| List a user's conversations, most recent first, each with a short preview. Query: |
| Replayable transcript of one conversation. Query: |
| Bidirectional voice session with the travel agent. |
Post-sales
A dedicated agent for travellers who already hold a booking: booking lookup, ticket retrieval, change and cancellation guidance, and carrier T&C answers. It also works anonymously (FAQ and T&C only) when no booking credentials are supplied.
Method & path | Purpose |
| Single-shot post-sales turn. |
| Streamed post-sales chat (NDJSON). |
| List post-sales conversations for a user. |
| Transcript of one post-sales conversation. |
| Bidirectional post-sales voice session. |
The post-sales request body accepts an optional bookings array. Each entry identifies a booking either by booking_id, or by booking_number + last_name + email. Omit it (or send []) for anonymous support.
Supporting endpoints
Method & path | Purpose |
GET /settings/{rpn} | Effective agent configuration and UI feature flags for a retailer. Always returns 200 — an unconfigured retailer resolves to defaults. |
GET /api/memories | List the travel memories stored for the authenticated user. |
DELETE /api/memories | Delete all memories for the user. |
DELETE /api/memories/{memory_id} | Delete one memory. |
How to Use — Chat
POST /chat
Request Body
{
"user_id": "<unique user id>",
"conversation_id": "<unique conversation id>",
"text": "<text input>"
}
Optional fields for personalisation: user_preferences, user_location ({"latitude": …, "longitude": …}, enables "from my location" queries), context_mode (memory | profile | none), and bookings when the user has already verified booking credentials.
Response
{
"text": "<response from agent>",
"response_event_id": "<id of the event that produced the text>"
}
response_event_id correlates the reply with the stored conversation — the history endpoints return the same value as event_id. It is null when the text is not agent output, for example a safety block or a fallback message.
POST /chat/stream
Same request body. The response is application/x-ndjson: one JSON object per line, emitted as the run progresses.
{
"event_type": "final_output | partial_output | function_call | function_response | unknown",
"text_chunk": "<response chunk from agent>" | null,
"function_calls": [{ "name": "…", "args": { … }, "thought": "…" }] | null,
"function_responses": [{ "name": "…", "response": { … }, "thought": "…" }] | null,
"response_event_id": "…" | null
}event_type | Meaning |
| An incremental text chunk of the current message. Accumulate and render. |
| The agent is calling a tool. Carries |
| The tool result. The raw payload is available if you want to render it — a results list, a map, a seat plan — otherwise show the |
| End of the response. |
| Anything not matching the schema above. Ignore safely |
Handling the stream
- Open the stream Send the request and read the response line by line.
- Accumulate text On
partial_output, appendtext_chunkto the message currently being rendered. - Show tool activity On
function_call/function_response, show thethoughtas a "thinking" indicator, and optionally use the raw response to render richer output. - Finish the turn On
final_output, the turn is over.
A sequence of partial_output events followed by an event of a different type marks the end of a message, not of the turn. One turn can contain several messages, for example: "I'll search for your trip" → tool call → tool response → "I found these trips…".
Example
curl --no-buffer -N -X POST "https://s.api.distribusion.com/agent/chat/stream" \
-H "Content-Type: application/json" \
-H "api-key: <your-agent-api-key>" \
-d '{
"user_id": "user-123",
"conversation_id": "conv-456",
"text": "from Mexico City to Monterrey today from 7pm"
}'
{"event_type":"function_call","function_calls":[{"args":{"query":"Mexico City","locale":"en"},"name":"search_cities","thought":"Searching for Mexico City"}]}
{"event_type":"function_response","function_responses":[{"name":"search_cities","response":{"cities":[{"code":"MXMCI","name":"Mexico City","country_code":"MX"}]}}]}
{"event_type":"function_call","function_calls":[{"args":{"departure_city_code":"MXMCI","arrival_city_code":"MXMTY","departure_date":"2026-03-20","departure_start_time":"19:00","locale":"en"},"name":"connections_find","thought":"Finding trips..."}]}
{"event_type":"function_response","function_responses":[{"name":"connections_find","response":{"connections":[{"connection_id":"SDIA-MXMCICIU-MXMTYMBU-…","departure_time":"2026-03-20T19:00:00","arrival_time":"2026-03-21T08:40:00","price":61.68,"currency":"EUR","carrier":{"code":"SDIA","name":"Senda Diamante"}}]}}]}
{"event_type":"partial_output","text_chunk":"Here are the connections I found from Mexico City to Monterrey"}
{"event_type":"partial_output","text_chunk":" for today, departing from 7 PM: …"}
{"event_type":"final_output","text_chunk":"","response_event_id":"…"}Voice
Voice is a bidirectional WebSocket. Connect to wss://s.api.distribusion.com/agent/voice/stream (or the post-sales equivalent).
- Open the socket Send one JSON message first, containing
user_id,conversation_idandapi_key. - Exchange audio Then exchange binary PCM audio frames, plus JSON control messages.
The voice agent shares the travel agent's tools and conversation storage, so a voice session and a chat session on the same conversation_id continue the same thread.
Suggested UI
These endpoints are meant to be integrated in a chat-like UI, as showcased below (streaming response displaying function calls).
Features
Feature | What it does |
Location discovery | Resolves free-text place names to cities, stations and areas, including nearby-station and "from my location" queries. |
Connection search | Finds connections for a route and date, including multi-leg itineraries, and can broaden or narrow the search conversationally. |
Offer and fare comparison | Compares fare classes, prices and journey types, and explains the trade-offs in plain language. |
Vacancy and seats | Confirms availability and seat/fare options before the traveller commits. |
Price calendar | Surfaces cheaper nearby dates so the user can shift a flexible trip. |
Cart and checkout | Builds a cart and produces a checkout link that hands the traveller to the booking flow. |
Carrier information and T&C | Answers luggage, accessibility, pet, change and refund questions from carrier terms and conditions. |
Post-sales support | Looks up an existing booking and helps with what comes after the sale, or answers anonymously when no booking is provided. |
Itinerary planning | For open-ended requests, plans a more strategic itinerary before searching. |
Personalisation and memory | Applies stated preferences and remembers useful facts across conversations. Fully controllable via |
Voice | Native low-latency speech-to-speech on the same agent and the same conversation. |
Multilingual | Replies in the user's language; |
Map-ready output | Station coordinates plus road-route polylines for bus and train segments. |
Conversation history | Server-side storage with list and replay endpoints, so a UI can be rehydrated after a refresh. |
Safety guardrails | Input and output filtering keeps the agent on-topic and prevents unsafe or off-brand replies. |
Per-retailer configuration | Tone, enabled capabilities, carriers and booking limits are configured per retailer and readable via |
Notes
- Streaming and voice need a long-lived connection. Use
s.api.distribusion.comfor those; the standard host times out first. - Do not buffer the NDJSON response. Disable client-side buffering (for example
curl --no-buffer -N) or the stream will only appear at the end. - Errors are returned as
{"error": "…", "detail": "…"}.400means the request or the API key is wrong,401/403an authentication or permission problem,404a missing conversation or resource,422a validation error, and503a temporary upstream problem worth retrying. - Operational endpoints (
/health,/metrics,/docs,/openapi.json) are not exposed publicly.
On this page
- Retailer Agent