Query API
The Nexus Platform provides a public query API that enables you to submit questions and receive AI-generated answers from your configured experiences. This endpoint is the core of the platform’s conversational AI capabilities and powers the chat widget.
Overview
The query API accepts natural language questions and returns AI-generated responses based on your experience’s knowledge base, tools, and configuration. Key features include:
- Optional authentication - Experiences can require access tokens or remain fully public
- Multi-turn conversations - Track conversations across multiple queries using session IDs
- Flexible user identification - Support for email addresses, UUIDs, or custom identifiers
- Origin validation - Optional allowlist for controlling access by domain
- Custom metadata - Attach tracking data to queries for analytics
Endpoint Details
URL: POST /api/v2/query
Authentication: Optional - depends on experience configuration
Content-Type: application/json
CORS: Fully supported with wildcard origin (*)
Rate Limiting: Standard platform rate limits apply per origin
Authentication
Some experiences may require authentication for query requests.
Providing an access token:
Include an Authorization header with a Bearer token:
fetch('https://nexus-api.uat.knowbl.com/api/v2/query', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
},
body: JSON.stringify({
text: 'What are your hours?',
experienceId: 'YOUR_EXPERIENCE_ID'
})
});Obtaining access tokens:
- Access tokens are obtained via
POST /v2/auth/access-tokens - Tokens must have the
query:executescope - See the Authentication Guide for details on token creation and management
Request Format
Submit queries as JSON with the following fields:
Required Fields
text (string)
The query text - the user’s question or message.
{
"text": "What are your business hours?"
}experienceId (string, UUID)
The UUID of the experience to query. This determines which knowledge base, tools, and configuration will be used to answer the query.
{
"experienceId": "550e8400-e29b-41d4-a716-446655440000"
}Optional Fields
userId (string, optional)
⚠️ Note: This field may be removed in a future version. For production applications, consider using the Sessions API to create sessions with userId before submitting queries.
User identifier for tracking and personalization. Supports multiple formats:
- Email address:
customer@example.com(case-insensitive) - UUID:
a1b2c3d4-e5f6-7890-abcd-ef1234567890 - Custom string: Any string up to 255 characters (e.g.,
user-12345)
Normalization: All userId values are automatically converted to lowercase for consistency.
Constraints:
- Minimum 1 character
- Maximum 255 characters
- Cannot contain whitespace or control characters
- Cannot be an empty string (use
nullor omit for anonymous queries)
{
"userId": "customer@example.com"
}sessionId (string, UUID, optional)
Session identifier for multi-turn conversations. Include the sessionId from a previous query response to maintain conversation context.
Important:
- If provided, must be a valid UUID
- System validates that the userId matches the session’s original userId
- Automatically created if not provided - returned in response for use in subsequent queries
{
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}timestamp (string, ISO 8601, optional)
Query timestamp. Defaults to the current time if not provided.
{
"timestamp": "2025-10-28T10:30:00.000Z"
}metadata (object, optional)
⚠️ Note: This field may be removed in a future version. For production applications, consider using the Sessions API to create sessions with metadata before submitting queries, or update session metadata during the conversation.
Custom key-value pairs for tracking and analytics. Use this to attach contextual information about the query source, user environment, or application state.
Common use cases:
- Source tracking:
{ "source": "mobile-app" } - Device information:
{ "deviceType": "iOS", "appVersion": "2.1.0" } - Page context:
{ "pagePath": "/account/orders" } - Campaign tracking:
{ "campaign": "summer-sale-2025" }
{
"metadata": {
"source": "mobile-app",
"deviceType": "iOS",
"appVersion": "2.1.0",
"pagePath": "/account/orders"
}
}Response Format
The API returns a minimal response optimized for widget consumption:
Response Fields
queryId (string, UUID)
Unique identifier for this query. Use this for debugging, support tickets, or analytics tracking.
{
"queryId": "01234567-89ab-cdef-0123-456789abcdef"
}answer (string)
The AI-generated answer to the query. This is the primary response content to display to the user.
{
"answer": "Our business hours are Monday through Friday, 9 AM to 5 PM EST."
}sessionId (string, UUID)
Session identifier for this conversation. Always returned, even for first queries. Store this value and include it in subsequent queries to maintain conversation context.
{
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}timestamp (string, ISO 8601)
Response timestamp indicating when the query was processed.
{
"timestamp": "2025-10-28T10:30:15.234Z"
}format (string, optional)
Answer format indicator. Reserved for future use to support different content types.
Possible values (planned):
"markdown"- Markdown-formatted text"text"- Plain text"html"- HTML content
Currently, all responses are in plain text/markdown format.
{
"format": "markdown"
}actions (array, optional)
Array of action buttons to display alongside the answer. Actions enable rich interactions like triggering handovers, opening URLs, or sending follow-up queries.
Action structure:
id(string) - Unique action identifierlabel(string) - Button texticon(object, optional) - Icon configurationtype(string) - Icon type:"svg","url", or"emoji"content(string) - Icon content (SVG markup, URL, or emoji character)
action(object) - Action to performtype(string) - Action type:"trigger_handover","open_url","send_event", or"send_query"- Additional type-specific fields
style(object, optional) - Custom stylingbehavior(object, optional) - Behavior configurationvisibility(object, optional) - Visibility rules
Example:
{
"actions": [
{
"id": "talk-to-agent",
"label": "Talk to an Agent",
"icon": {
"type": "emoji",
"content": "💬"
},
"action": {
"type": "trigger_handover",
"agentType": "support"
}
}
]
}Code Examples
Anonymous Query
Submit a query without user identification:
// Anonymous query without user identification
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "Tell me about your services",
experienceId: "your-experience-id",
}),
});
const data = await response.json();
console.log(data);
// {
// queryId: "01234567-89ab-cdef-0123-456789abcdef",
// answer: "We offer...",
// sessionId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
// timestamp: "2025-10-28T10:30:00.000Z"
// }
Query with User ID
Track queries for a specific user using email or custom identifier:
// Query with user identification (email format)
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "What are your business hours?",
experienceId: "your-experience-id",
userId: "customer@example.com",
}),
});
const data = await response.json();
console.log(data);
Query with Session Continuity
Maintain conversation context across multiple queries:
// Query with session continuity for multi-turn conversation
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "What about refund policies?",
experienceId: "your-experience-id",
userId: "customer@example.com",
sessionId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890", // From previous query
}),
});
const data = await response.json();
// Store sessionId for future queries
if (data.sessionId) {
localStorage.setItem("nexus-session-id", data.sessionId);
}
Query with Metadata
Include custom metadata for tracking and analytics:
// Query with custom metadata for tracking
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text: "What's the status of my order?",
experienceId: "your-experience-id",
userId: "user@company.com",
sessionId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
metadata: {
source: "mobile-app",
deviceType: "iOS",
appVersion: "2.1.0",
pagePath: "/account/orders",
},
}),
});
const data = await response.json();
Authenticated Query
Submit a query with access token authentication (required for experiences that require authentication):
// Query with access token authentication
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_ACCESS_TOKEN", // Include access token
},
body: JSON.stringify({
text: "What are your business hours?",
experienceId: "YOUR_EXPERIENCE_ID",
}),
});
const data = await response.json();
// Store session ID for subsequent queries
const sessionId = data.sessionId;
console.log("Answer:", data.answer);
console.log("Session ID:", sessionId);
cURL Examples
Test the API directly from the command line:
Anonymous Query
# Anonymous query
curl -X POST "https://nexus-api.uat.knowbl.com/api/v2/query" \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{
"text": "Tell me about your services",
"experienceId": "your-experience-id"
}'
Complete Query with All Fields
# Complete query with all fields
curl -X POST "https://nexus-api.uat.knowbl.com/api/v2/query" \
-H "Content-Type: application/json" \
-H "Origin: https://example.com" \
-d '{
"text": "What are your business hours?",
"experienceId": "your-experience-id",
"userId": "customer@example.com",
"sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"metadata": {
"source": "api-test",
"timestamp": "2025-10-28T10:30:00Z"
}
}'
Authenticated Query
curl -X POST "https://nexus-api.uat.knowbl.com/api/v2/query" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"text": "What are your business hours?",
"experienceId": "YOUR_EXPERIENCE_ID"
}'
Error Handling
The query API returns standard HTTP status codes with detailed error messages:
400 Bad Request
Request validation failed. Common causes:
- Invalid JSON: Malformed request body
- Missing required fields:
textorexperienceIdnot provided - Invalid field values:
experienceIdis not a valid UUIDsessionIdis not a valid UUIDuserIdcontains whitespace or control charactersuserIdexceeds 255 characters
- Inactive workspace: The experience’s workspace is not active
Example:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation failed",
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}401 Unauthorized
Authentication required but not provided, or the provided access token is invalid.
Common causes:
- Experience requires authentication but no token was provided
- Access token is expired or invalid
- Access token is missing the
query:executescope
Example:
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Access token required for this experience",
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}Solution:
- Obtain a valid access token via
POST /v2/auth/access-tokens - Ensure the token has the
query:executescope - Include the token in the
Authorization: Bearer <token>header
403 Forbidden
Request forbidden for one of the following reasons:
1. Origin not allowed: The request origin doesn’t match any patterns in the experience’s allowedOrigins configuration.
Example:
{
"statusCode": 403,
"error": "Forbidden",
"message": "Origin https://unauthorized-site.com is not allowed for this experience",
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}Solution: Contact the workspace administrator to add your domain to the allowed origins list in the experience configuration.
2. Insufficient scopes: Access token provided but missing required query:execute scope.
Example:
{
"statusCode": 403,
"error": "Forbidden",
"message": "Insufficient scopes",
"required": [
"query:execute"
],
"missing": [
"query:execute"
],
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}Solution: Request a new access token with the query:execute scope included.
404 Not Found
Experience not found. The provided experienceId doesn’t exist or has been deleted.
Example:
{
"statusCode": 404,
"error": "Not Found",
"message": "Experience not found",
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}500 Internal Server Error
Unexpected server error occurred while processing the query. These errors are logged for investigation.
Example:
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"timestamp": "2025-10-28T10:30:00.000Z",
"path": "/v2/query"
}Note: If you receive this error, the queryId in your last successful response can help with debugging.
Best Practices
Session Management
Store the session ID immediately:
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: "Hello",
experienceId: "your-experience-id",
}),
});
const data = await response.json();
// Store for subsequent queries
if (data.sessionId) {
localStorage.setItem("nexus-session-id", data.sessionId);
}
Use the same session ID for the entire conversation:
const sessionId = localStorage.getItem("nexus-session-id");
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: "What about refund policies?",
experienceId: "your-experience-id",
sessionId: sessionId, // Maintains context
}),
});
Origin Allowlist Configuration
If you control the experience configuration, set up origin validation to prevent unauthorized access:
- Navigate to experience settings in the admin UI
- Add allowed origin patterns under Safety Settings
- Patterns support wildcards:
https://*.example.com
Without origin validation: Anyone can query your experience from any website.
With origin validation: Only requests from allowed domains will succeed.
Metadata Usage Patterns
Track user journey:
metadata: {
source: "checkout-page",
cartValue: 129.99,
itemCount: 3,
step: "payment"
}Monitor application context:
metadata: {
appVersion: "2.1.0",
platform: "iOS",
networkType: "wifi",
screenSize: "375x812"
}Campaign attribution:
metadata: {
campaign: "summer-sale-2025",
utmSource: "email",
utmMedium: "newsletter",
utmContent: "cta-button"
}Widget Integration
The Nexus Chat Widget automatically handles query submission, session management, error handling, and authentication. See the Chat Widget documentation for integration details.
Key widget benefits:
- Automatic session ID persistence
- Built-in error handling and retries
- Origin management
- Optional access token support
- Message rendering with markdown support
- Action button handling
Widget authentication:
The widget supports optional authentication via the accessToken configuration:
// Initialize with access token
window.NexusChatWidget.init({
experienceId: 'YOUR_EXPERIENCE_ID',
apiUrl: 'https://api.your-domain.com',
accessToken: 'YOUR_ACCESS_TOKEN'
});
// Update token dynamically
widget.updateAccessToken('NEW_ACCESS_TOKEN');Error Recovery
Handle network errors gracefully:
try {
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
/* ... */
});
if (!response.ok) {
const error = await response.json();
console.error("Query failed:", error.message);
// Show user-friendly error message
return;
}
const data = await response.json();
// Process successful response
} catch (error) {
console.error("Network error:", error);
// Show offline message
}
Implement retry logic for transient failures:
async function queryWithRetry(body, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
if (response.ok) {
return await response.json();
}
// Don't retry client errors (4xx)
if (response.status >= 400 && response.status < 500) {
throw new Error(await response.text());
}
// Retry server errors (5xx)
if (i < maxRetries - 1) {
await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
} catch (error) {
if (i === maxRetries - 1) {
throw error;
}
await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
Integration with Sessions
The query API works seamlessly with the session management API for multi-turn conversations and advanced tracking.
Automatic vs. Explicit Session Creation
Automatic (recommended for simple use cases):
- Don’t provide a
sessionIdin your first query - The API automatically creates a session and returns the
sessionId - Store and reuse this
sessionIdin subsequent queries
Explicit (for advanced control):
- Pre-create sessions using the Sessions API before the first query
- Useful when you need to set initial metadata or track session creation separately
- Requires bearer token authentication (see Authentication Guide)
// 1. Create a session
const sessionResponse = await fetch("https://nexus-api.uat.knowbl.com/api/v2/sessions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
experienceId: "your-experience-id",
userId: "customer@example.com",
metadata: {
source: "support-chat",
agent: "none",
},
}),
});
const session = await sessionResponse.json();
// 2. Use session ID in queries
const queryResponse = await fetch("https://nexus-api.uat.knowbl.com/api/v2/query", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: "How do I reset my password?",
experienceId: "your-experience-id",
sessionId: session.id,
}),
});
Advanced Session Management
For production applications, you may want to:
- Update session metadata as conversations progress to track state changes
- Mark sessions as complete when conversations end to improve analytics
- List and retrieve sessions for reporting and debugging
For detailed information on session lifecycle, metadata management, and session state transitions, see the Sessions documentation.
Next Steps
- Sessions API - Learn about session lifecycle and management
- Chat Widget - Integrate the pre-built chat widget
- API Reference - Complete API documentation