Marqo Conversational Agent API
Overview
The Conversational Agent API provides intelligent, conversational product discovery with query expansion, contextual recommendations, and real-time streaming responses. The system understands user intent, asks clarifying questions when needed, and organizes results into meaningful categories with natural language explanations.
Prerequisites
- A Marqo Cloud account
- Your
x-marqo-index-idvalue (copy it from the Quick Start code snippets for your index in the Marqo Console) - An existing ecommerce index with products (add products guide)
- Access to the Conversational Agent API (contact Marqo for access)
Endpoints
Conversational Search
Stream conversational search results with categorized products and intelligent messaging. This is the main endpoint for conversational product discovery.
Endpoint: GET /indexes/{index_name}/agentic-search/converse
Headers:
x-marqo-index-id: {index_id}(required)
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
payload | string | Yes | Base64-encoded JSON containing the request parameters (see below) |
Payload Parameters (JSON, then base64-encoded):
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
q | string | Yes | - | User query |
sessionId | string | No | null | Session identifier |
userId | string | No | null | User identifier |
conversationId | string | No | - | Conversation identifier (returned from a previous response) for maintaining context |
categoryResultLimit | integer | No | 6 | Number of results per category |
maxCategories | integer | No | 4 | Maximum number of categories the agent will return |
filter | string | No | - | Query filter using Marqo's filter DSL (e.g., "availability:true") |
attributesToRetrieve | array | No | Default fields | Product fields to return (e.g., ["productTitle", "variantTitle", "price", "variantImageUrl", "_id"]) |
documentIds | array | No | - | Product document IDs to use as context (e.g., for PDP page questions) |
contextFields | array | No | All fields | Fields to include from the document context (e.g., ["material", "description"]) |
imageUrls | array | No | - | Image URLs to include in the query (max 5, must be valid URLs) |
categoriesAfterMessage | boolean | No | false | When true, category-hits events are always sent after the message events (see Response Event Ordering) |
divisionSeed | string | No | - | Hint which product division the user is browsing from (see Division Seed) |
Example Request: With Product Context
curl -G 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/converse' \
--header 'x-marqo-index-id: abc123-my-ecom-store' \
--data-urlencode "payload=$(echo -n '{
"conversationId": "3fd8b45def95c8a98da1cfda23543699144cee5d9c89ae143040bca4ff0636e9",
"documentIds": ["1298739082732"],
"q": "I need outfits for a tropical vacation",
"sessionId": "session-xyz789",
"userId": "user-123",
"categoryResultLimit": 6,
"filter": "availability:true",
"attributesToRetrieve": [
"productTitle",
"variantTitle",
"price",
"variantImageUrl",
"_id"
]
}' | base64 | tr -d '\n')"
Example Request: Simple Query
curl -G 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/converse' \
--header 'x-marqo-index-id: abc123-my-ecom-store' \
--data-urlencode "payload=$(echo -n '{
"q": "red dress",
"sessionId": "session-001",
"userId": "user-456"
}' | base64 | tr -d '\n')"
Response Events
The conversational search endpoint streams responses as Server-Sent Events (SSE). Each event has an event: field identifying its type and a data: field containing a JSON payload.
message
Streamed text deltas from the agent's conversational response. These arrive incrementally as the agent generates text and should be concatenated to build the full message.
event: message
data: {"message":"I'd be happy to help you find the perfect jacket! "}
event: message
data: {"message":"To give you the best recommendations:\n\n- What type of jacket are you looking for?"}
Fields:
message(string): A text delta to append to the agent's response
suggestions
Follow-up query suggestions generated by the agent based on the current conversation context. Display these as clickable prompts to help users continue exploring.
event: suggestions
data: {"suggestions":["show me trending items for her","what are popular tech gifts?","something unique and trending"]}
Fields:
suggestions(array of strings): Suggested follow-up queries the user might want to ask
category-hits
Search results grouped by category.
event: category-hits
data: {"categoryHits":[{"category":"Summer Dresses","query":"summer floral dresses","confidence":0.9,"hits":[{"_id":"dress_001","productTitle":"Red Sequin Dress","price":89.99},{"_id":"dress_002","productTitle":"Black Silk Gown","price":129.99}]}]}
Fields:
categoryHits(array): Array of category groupscategory(string): Category name (e.g., "Summer Dresses", "Casual Jackets")query(string): The search query the agent used to retrieve products in this categoryconfidence(number): The agent's confidence score for this category (0–1)hits(array): Array of product documents matching this categoryappliedFilter(string, optional): The filter that was applied to this category's searchfilterDropped(boolean, optional):trueif the agent's filter was dropped due to producing zero resultsoriginalFilter(string, optional): The filter that was dropped, present whenfilterDroppedistrue
title
Emitted on the first turn of a new conversation with a generated title. The title is a short summary of the conversation topic, generated automatically by the agent. Use this to display a heading for the conversation in your UI (e.g., in a conversation history sidebar).
event: title
data: {"title":"Running Shoes"}
Fields:
title(string): A short title summarizing the conversation topic
conversation-id
Emitted after the conversation is saved. Use this ID in subsequent requests to continue the conversation.
event: conversation-id
data: {"conversationId":"3fd8b45def95c8a98da1cfda23543699144cee5d9c89ae143040bca4ff0636e9"}
Fields:
conversationId(string): Unique identifier for this conversation
error
Emitted when an error occurs during processing.
event: error
data: {"error":"Failed to retrieve document doc_123: not found","status":404}
Fields:
error(string): Error messagestatus(number, optional): HTTP status code
stream-end
Marks the end of the SSE stream. No further events will be sent.
event: stream-end
data: {}
Response Event Ordering
By default, category-hits events are streamed as soon as search results are available, which means they may arrive before the message events. This allows clients to render product results immediately while the agent's text response is still being generated.
If you prefer to display category results after the agent's message (for example, to show the conversational text first), set categoriesAfterMessage to true in the payload. When enabled, category-hits events are buffered internally and sent after all message and suggestions events.
Conversation Starters
Generate conversation starters based on your most popular queries from your analytics data.
Endpoint: GET /indexes/{index_name}/agentic-search/conversation-starters
Headers:
x-marqo-index-id: {index_id}(required)
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
maxStarters | integer | No | 4 | Number of conversation starters to return. Must be between 1 and 20 |
division | string | No | null | Product division filter to generate division-specific starters. Allowed values: men, mens, women, womens, kid, kids |
Example Request:
curl 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/conversation-starters?maxStarters=4&division=women' \
--header 'x-marqo-index-id: abc123-my-ecom-store'
Example Response:
[
"Show me running shoes for a marathon",
"Help me find a gift for a birthday",
"I'm looking for the perfect backpack",
"What's trending in sneakers right now?"
]
The response is an array of conversation starter strings.
PDP Query Suggestions
Generate contextual search query suggestions based on a specific product. This endpoint helps users discover related products or learn more about a product they're viewing.
Endpoint: POST /indexes/{index_name}/agentic-search/chat-suggestions
Headers:
Content-Type: application/jsonx-marqo-index-id: {index_id}(required)
Request Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
documentId | string | Yes | - | Product document identifier (_id field) |
sessionId | string | Yes | - | User session identifier |
userId | string | Yes | - | User identifier |
maxSuggestions | integer | No | 5 | Maximum number of suggestions to return |
minSuggestions | integer | No | 1 | Minimum number of suggestions to return |
contextFields | string[] | No | ["productTitle", "variantTitle"] | Document fields to include as context for suggestion generation. When provided, only matching fields (case-insensitive) are passed to the model. When omitted, defaults to productTitle and variantTitle. Image context (variantImageUrl/productMainImageUrl) is always included automatically when present. |
Example Request:
curl -X POST 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/chat-suggestions' \
--header 'Content-Type: application/json' \
--header 'x-marqo-index-id: abc123-my-ecom-store' \
--data '{
"documentId": "273301208",
"sessionId": "session-abc123",
"userId": "user-28389290",
"maxSuggestions": 5,
"minSuggestions": 1,
"contextFields": ["material", "description"]
}'
Example Response:
[
"What heels would go well with this?",
"What is the material made out of?",
"What do people say about this product?"
]
The response is an array of suggested queries that users might want to ask about the product.
Get Conversation
Retrieve the history of a previous conversation by its ID.
Endpoint: GET /indexes/{index_name}/agentic-search/conversations/{conversation_id}
Headers:
x-marqo-index-id: {index_id}(required)
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
index_name | string | Yes | The name of your index |
conversation_id | string | Yes | The conversation ID returned from a previous converse response |
Example Request:
curl 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/conversations/3fd8b45def95c8a98da1cfda23543699144cee5d9c89ae143040bca4ff0636e9' \
--header 'x-marqo-index-id: abc123-my-ecom-store'
Example Response:
{
"conversationId": "3fd8b45def95c8a98da1cfda23543699144cee5d9c89ae143040bca4ff0636e9",
"title": "Tropical Vacation Outfits",
"conversation": [
{
"role": "user",
"message": "I need outfits for a tropical vacation"
},
{
"role": "agent",
"message": "Here are some great options for a tropical getaway!",
"categories": [
{
"query": "tropical vacation dresses",
"category": "Summer Dresses",
"confidence": 0.9,
"hits": ["dress_001", "dress_002"]
}
]
}
]
}
Response Fields:
conversationId(string): The conversation identifiertitle(string, optional): A short title summarizing the conversation topicconversation(array): Array of messages in chronological orderrole(string): Either"user"or"agent"message(string): The message contentcategories(array, optional, agent only): Search categories from the agent's responsequery(string): The search query usedcategory(string): The category nameconfidence(number): Confidence score (0–1)hits(array of strings): Product document IDs returned
List Conversations
List all conversations for a specific user, sorted by most recently updated first.
Endpoint: GET /indexes/{index_name}/agentic-search/conversations
Headers:
x-marqo-index-id: {index_id}(required)
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | string | Yes | The user identifier to list conversations for |
Example Request:
curl 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/conversations?userId=user-123' \
--header 'x-marqo-index-id: abc123-my-ecom-store'
Example Response:
{
"conversations": [
{
"conversationId": "3fd8b45def95c8a98da1cfda23543699144cee5d9c89ae143040bca4ff0636e9",
"title": "Tropical Vacation Outfits",
"createdAt": 1717012800000,
"updatedAt": 1717016400000
},
{
"conversationId": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"title": "Running Shoes",
"createdAt": 1716926400000,
"updatedAt": 1716930000000
}
]
}
Response Fields:
conversations(array): Array of conversation summaries, sorted byupdatedAtdescending (most recent first)conversationId(string): Unique identifier for the conversationtitle(string): A short title summarizing the conversation topiccreatedAt(number): Timestamp (milliseconds since epoch) when the conversation was createdupdatedAt(number): Timestamp (milliseconds since epoch) when the conversation was last updated
Agentic Conversation Behavior Overview
Context Management
The system maintains conversation context across interactions:
- Context Continuity: Previous conversation context is used to inform current responses
- Product Context: When
documentIdsare provided, the system fetches those products and uses their information to provide more relevant responses. UsecontextFieldsto limit which product fields are included. - Session Tracking:
sessionIdanduserIdhelp maintain context throughout a user's session
Question Triggering - Ambiguous Queries
The system automatically asks clarifying questions when user queries are ambiguous or too broad.
Examples:
- Query:
"jacket"→ System asks: "What type of jacket are you looking for (winter coat, rain jacket, casual jacket, work blazer)?" - Query:
"shoes"→ System asks clarifying questions about style, occasion, or gender - Query:
"dress"→ System asks about occasion, style, or fit preferences
When Questions Are Triggered:
- Queries that are too broad (single word product categories)
- Queries missing important context (style, occasion, gender, features)
- Queries that could match many different product types
Division Seed
The divisionSeed parameter tells the agent which product division (e.g. Women's, Men's, Kids) the user is currently browsing. The agent uses this as a default filter for searches without the user needing to state it explicitly.
Allowed values: men, mens, women, womens, kid, kids, beauty
Any other value returns a 400 error.
Example Request:
curl -G 'https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/converse' \
--header 'x-marqo-index-id: abc123-my-ecom-store' \
--data-urlencode "payload=$(echo -n '{
"q": "show me summer dresses",
"divisionSeed": "womens",
"sessionId": "session-001",
"userId": "user-456"
}' | base64 | tr -d '\n')"
Behavior:
- The agent defaults searches to the specified division (e.g. applying a division filter for Women's products)
- If the user explicitly requests a different division (e.g. "show me men's jackets"), the agent switches to the appropriate division
- Once switched, the agent stays on the new division for subsequent messages until the conversation context indicates otherwise
- The division is not mentioned to the user unless they ask about it
Interaction with filter:
If you also pass a filter that includes a division constraint (e.g. productDivision:(WOMENS)), the server-side filter takes priority. The agent will not add a conflicting division filter from the seed. In general, prefer using divisionSeed over hardcoded division filters — it allows the agent to adapt when the user's intent changes, rather than being locked to a fixed filter.
Implementation Notes
Streaming Response Handling
When using the converse endpoint, you must handle Server-Sent Events (SSE). The response will stream multiple events, each containing different parts of the response.
Example: Using EventSource
EventSource does not support custom headers natively. If your setup allows the
x-marqo-index-id header to be set via other means (e.g., cookies or a proxy), you
can use EventSource with named event listeners:
const requestData = {
q: "red dress",
sessionId: "session-001",
userId: "user-456",
};
const payload = btoa(JSON.stringify(requestData));
const url = `https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/converse?payload=${encodeURIComponent(payload)}`;
const eventSource = new EventSource(url);
let agentMessage = "";
eventSource.addEventListener("message", (event) => {
const data = JSON.parse(event.data);
agentMessage += data.message;
});
eventSource.addEventListener("category-hits", (event) => {
const data = JSON.parse(event.data);
console.log("Categories:", data.categoryHits);
});
eventSource.addEventListener("suggestions", (event) => {
const data = JSON.parse(event.data);
console.log("Suggestions:", data.suggestions);
});
eventSource.addEventListener("title", (event) => {
const data = JSON.parse(event.data);
console.log("Conversation title:", data.title);
});
eventSource.addEventListener("conversation-id", (event) => {
const data = JSON.parse(event.data);
console.log("Conversation ID:", data.conversationId);
});
eventSource.addEventListener("error", (event) => {
const data = JSON.parse(event.data);
console.error("Server error:", data.error);
});
eventSource.addEventListener("stream-end", () => {
console.log("Full message:", agentMessage);
eventSource.close();
});
Example: Using fetch with ReadableStream (supports custom headers)
const requestData = {
q: "red dress",
sessionId: "session-001",
userId: "user-456",
};
const payload = btoa(JSON.stringify(requestData));
const url = `https://ecom.marqo-ep.ai/api/v1/indexes/my-ecom-store/agentic-search/converse?payload=${encodeURIComponent(payload)}`;
const response = await fetch(url, {
method: "GET",
headers: {
"x-marqo-index-id": "abc123-my-ecom-store",
},
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const parts = buffer.split("\n\n");
buffer = parts.pop();
for (const part of parts) {
const eventMatch = part.match(/^event: (.+)$/m);
const dataMatch = part.match(/^data: (.+)$/m);
if (!eventMatch || !dataMatch) continue;
const eventType = eventMatch[1];
const data = JSON.parse(dataMatch[1]);
switch (eventType) {
case "message":
console.log("Text delta:", data.message);
break;
case "category-hits":
console.log("Categories:", data.categoryHits);
break;
case "suggestions":
console.log("Suggestions:", data.suggestions);
break;
case "title":
console.log("Conversation title:", data.title);
break;
case "conversation-id":
console.log("Conversation ID:", data.conversationId);
break;
case "error":
console.error("Error:", data.error);
break;
case "stream-end":
console.log("Stream complete");
break;
}
}
}