Guides
Technical reference for the semantic search endpoint.
/v1/searchPerform semantic search across indexed documents. Returns relevant chunks without LLM processing.
httpContent-Type: application/json
json{ "datasetId": "string", "question": "string", "filters": [] }
| Parameter | Type | Required | Description |
|---|---|---|---|
datasetId | string | Yes* | Dataset to search (*optional with frontend token) |
question | string | Yes | Search query or question |
filters | array | No | Qdrant filters for metadata-based filtering |
bashcurl -X POST https://api.easyrag.com/v1/search \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "datasetId": "my-dataset", "question": "What is the refund policy?" }'
json{ "success": true, "data": [ { "score": 0.8924, "pageContent": "To reset your password, navigate to the login page...", "metadata": { "fileId": "f7a3b2c1-4d5e", "originalName": "user-manual.pdf", "customerId": "user_abc123", "datasetId": "my-dataset", "department": "support" } }, { "score": 0.8567, "pageContent": "For security purposes, passwords must be reset...", "metadata": { "fileId": "a1b2c3d4-5e6f", "originalName": "security-policy.pdf", "customerId": "user_abc123", "datasetId": "my-dataset" } } ] }
| Field | Type | Description |
|---|---|---|
success | boolean | Always true on success |
data | array | Array of search results (typically 5-10) |
data[].score | number | Similarity score (0-1, higher is better) |
data[].pageContent | string | Text chunk from document |
data[].metadata | object | Metadata about source document |
data[].metadata.fileId | string | Source file identifier |
data[].metadata.originalName | string | Source filename |
data[].metadata.customerId | string | Customer who owns the data |
data[].metadata.datasetId | string | Dataset containing the chunk |
data[].metadata.* | any | Additional custom metadata from upload |
json{ "success": true, "data": [] }
Apply metadata filters to narrow search results.
json{ "filters": [ { "key": "metadata_field", "match": { "value": "exact_value" } } ] }
json{ "datasetId": "company-docs", "question": "vacation policy", "filters": [ { "key": "department", "match": { "value": "HR" } } ] }
json{ "datasetId": "legal-docs", "question": "contract terms", "filters": [ { "key": "department", "match": { "value": "legal" } }, { "key": "year", "match": { "value": 2024 } }, { "key": "status", "match": { "value": "active" } } ] }
json{ "datasetId": "documents", "question": "active documents", "filters": [ { "key": "isArchived", "match": { "value": false } } ] }
json{ "datasetId": "shared-dataset", "question": "my documents", "filters": [ { "key": "userId", "match": { "value": "user_123" } } ] }
javascriptconst response = await fetch('https://api.easyrag.com/v1/search', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId: 'my-dataset', question: 'What are the key features?' }) }); const { data } = await response.json(); console.log(`Found ${data.length} results`);
pythonimport requests response = requests.post( 'https://api.easyrag.com/v1/search', headers={ 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' }, json={ 'datasetId': 'my-dataset', 'question': 'What are the key features?' } ) data = response.json() results = data['data']
javascriptconst response = await fetch('https://api.easyrag.com/v1/search', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId: 'company-docs', question: 'vacation policy', filters: [ { key: 'department', match: { value: 'HR' } }, { key: 'year', match: { value: 2024 } } ] }) });
Missing required fields
json{ "error": "datasetId and question are required" }
Dataset mismatch
json{ "error": "datasetId mismatch between token and request" }
json{ "error": "Missing API key or token" }
or
json{ "error": "Invalid API key or token" }
json{ "error": "INSUFFICIENT_CREDITS", "message": "You are out of credits. Please top up to continue.", "details": { "required": 1, "available": 0 } }
json{ "error": "Internal error" }
Results are ordered by similarity score (descending):
Chunks typically contain 200-400 words, depending on:
chunkSize parameter (default 300 tokens)chunkOverlap parameter (default 20 tokens)| Operation | Cost |
|---|---|
| 1 search | 0.1 credit |
| 10 searches | 1 credit |
| 100 searches | 10 credits |
Find relevant documents without AI generation:
javascriptconst { data } = await search('company-docs', 'meeting notes Q4 2024'); const files = [...new Set(data.map(r => r.metadata.originalName))]; console.log('Relevant files:', files);
Get context for your own LLM:
javascriptconst { data } = await search('knowledge-base', userQuestion); const context = data .map(r => r.pageContent) .join('\n\n'); const answer = await yourLLM.complete({ system: 'Answer based on context', messages: [ { role: 'system', content: context }, { role: 'user', content: userQuestion } ] });
Search user-specific documents:
javascriptconst { data } = await search('shared-dataset', query, { filters: [ { key: 'userId', match: { value: currentUserId } } ] });
| Feature | /v1/search | /v1/query |
|---|---|---|
| Returns | Raw chunks | AI-generated answer |
| LLM | No | Yes (GPT-4) |
| Streaming | No | Yes |
| Cost | 0.1 credit | 0.1 credit |
| Use Case | Custom chat, discovery | Ready answers |
| Speed | ~500ms | ~2-5s |
Use /v1/search when:
Use /v1/query when:
javascript// ✅ Good: Natural question await search('docs', 'How do I reset my password?'); // ❌ Bad: Keywords only await search('docs', 'password reset');
javascript// ✅ Good: Backend enforces filters app.post('/api/search', authenticateUser, async (req, res) => { const results = await easyragSearch({ datasetId: 'shared-docs', question: req.body.question, filters: [ { key: 'userId', match: { value: req.user.id } } ] }); res.json(results); }); // ❌ Bad: Client controls filters app.post('/api/search', async (req, res) => { const results = await easyragSearch({ datasetId: 'shared-docs', question: req.body.question, filters: req.body.filters // Client can change! }); res.json(results); });
javascriptconst { data } = await search(datasetId, question); if (data.length === 0) { console.log('No results found'); } else if (data[0].score < 0.7) { console.log('Results may not be very relevant'); }
javascriptdata.forEach(result => { console.log(`Score: ${result.score.toFixed(3)}`); console.log(`From: ${result.metadata.originalName}`); console.log(`Content: ${result.pageContent}`); console.log('---'); });
typescriptinterface SearchRequest { datasetId: string; question: string; filters?: Filter[]; } interface Filter { key: string; match: { value: string | number | boolean; }; } interface SearchResponse { success: true; data: SearchResult[]; } interface SearchResult { score: number; pageContent: string; metadata: { fileId: string; originalName: string; customerId: string; datasetId: string; [key: string]: any; // Custom metadata }; }
POST /v1/query - AI-generated answersPOST /v1/files/upload - Upload searchable filesGET /v1/files - List indexed files