Integrations
Queria is designed to be integrated within proprietary applications. This guide outlines the available integration methods, from the embeddable widget to server-to-server communication.
Embeddable widget
The fastest way to add Queria to a website or company portal.
Basic install
Add the following HTML code before the closing </body> tag:
<script src="https://cdn.queria.pro/widget.js"></script>
<script>
Queria.init({
apiKey: 'qk_live_abc123def456ghi789jkl012',
theme: 'light',
position: 'bottom-right',
language: 'en'
});
</script>Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | - | Domain-restricted API Key (required) |
theme | string | light | Theme: light, dark, auto |
position | string | bottom-right | Position: bottom-right, bottom-left |
language | string | it | Interface language: it, en |
primaryColor | string | #2563eb | Primary color (hex) |
title | string | AI Assistant | Title shown in the header |
placeholder | string | Type a question... | Input field placeholder |
topicId | string | - | Limits search to a specific topic |
width | number | 400 | Widget width in pixels |
height | number | 600 | Widget height in pixels |
Advanced customization
<script>
Queria.init({
apiKey: 'qk_live_abc123def456ghi789jkl012',
theme: 'dark',
position: 'bottom-right',
primaryColor: '#059669',
title: 'Document Support',
placeholder: 'Search company documents...',
topicId: 'topic_contracts',
onReady: function() {
console.log('Queria widget loaded');
},
onMessage: function(message) {
// Callback for every received message
analytics.track('queria_response', { query: message.query });
}
});
</script>Programmatic control
// Open the widget
Queria.open();
// Close the widget
Queria.close();
// Send a message programmatically
Queria.send('What is the return policy?');
// Destroy the instance
Queria.destroy();REST API integration
For deeper integrations, use the REST API directly with server-to-server authentication.
Recommended architecture
+-----------------+ +------------------+ +-----------------+
| Your App |---->| Your Backend |---->| Queria API |
| (Frontend) | | (Server) | | |
+-----------------+ +------------------+ +-----------------+The API Key must live exclusively on your backend. Your app's frontend communicates with your server, which in turn forwards requests to Queria.
Node.js example
const express = require('express');
const app = express();
const QUERIA_API_KEY = process.env.QUERIA_API_KEY; // qk_live_abc123...
const QUERIA_BASE_URL = 'https://api.queria.pro';
app.post('/api/ask', async (req, res) => {
const { question, sessionId } = req.body;
const response = await fetch(`${QUERIA_BASE_URL}/api/public/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': QUERIA_API_KEY
},
body: JSON.stringify({
message: question,
sessionId: sessionId
})
});
const data = await response.json();
res.json({
answer: data.data.response,
sources: data.data.sources
});
});Python example
import requests
import os
QUERIA_API_KEY = os.environ['QUERIA_API_KEY']
QUERIA_BASE_URL = 'https://api.queria.pro'
def ask_queria(question: str, session_id: str = None) -> dict:
response = requests.post(
f'{QUERIA_BASE_URL}/api/public/chat',
headers={
'Content-Type': 'application/json',
'X-API-Key': QUERIA_API_KEY
},
json={
'message': question,
'sessionId': session_id
}
)
response.raise_for_status()
result = response.json()
return {
'answer': result['data']['response'],
'sources': result['data']['sources']
}Use cases
CRM integration
Embed document search in your CRM to let operators find contracts, offers and customer documentation directly from the management UI.
// Search documents for a specific customer
const results = await fetch(`${QUERIA_BASE_URL}/api/public/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': QUERIA_API_KEY
},
body: JSON.stringify({
message: `Find active contracts for customer ${customerName}`,
sessionId: `crm_${customerId}`
})
});ERP integration
Connect financial documents (invoices, orders, delivery notes) to enable intelligent searches on accounting and warehouse data.
Company portal
Add an AI assistant to the company intranet for internal knowledge base consultation: manuals, operating procedures, HR policies.
Customer support
Automate answers to frequently asked questions with precise citations from official documents, reducing response time and improving support quality.
Authentication for integrations
| Scenario | Method | Notes |
|---|---|---|
| Widget on public site | API Key + domain restriction | The domain must match |
| Backend-to-backend | API Key | Keep the key on the server |
| App with user login | JWT | Each user has their own token |
| Mobile app | JWT + refresh token | Handle automatic refresh |
Best practices
Error handling
Implement a retry strategy with exponential backoff to handle transient errors:
async function queriaRequest(payload, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(`${QUERIA_BASE_URL}/api/public/chat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': QUERIA_API_KEY
},
body: JSON.stringify(payload)
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 5;
await sleep(retryAfter * 1000);
continue;
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}Rate limit handling
Monitor X-RateLimit-Remaining headers and slow down requests when the budget approaches zero. For high loads, contact support for custom limits.
Streaming for real-time responses
For interactive UIs, always use the streaming endpoint (/api/public/chat/stream) to show the answer progressively, improving the perception of responsiveness.
Caching
Implement an application-side cache for repeated queries. Queria already applies internal caching, but a local cache reduces latency and quota usage:
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function cachedQuery(question) {
const key = question.toLowerCase().trim();
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const result = await queriaRequest({ message: question });
cache.set(key, { data: result, timestamp: Date.now() });
return result;
}