API Reference
API keys and token endpoints
Technical reference for authentication endpoints.
/v1/tokens/createCreate a frontend token for browser/mobile applications.
Required: API key only (frontend tokens cannot create tokens)
httpAuthorization: Bearer YOUR_API_KEY Content-Type: application/json
json{ "datasetId": "string", "ttlSeconds": number }
| Parameter | Type | Required | Default | Constraints | Description |
|---|---|---|---|---|---|
datasetId | string | Yes | - | 1-100 chars | Dataset the token can access |
ttlSeconds | number | No | 3600 | 1-86400 | Token lifetime in seconds (max 24 hours) |
json{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600 }
| Field | Type | Description |
|---|---|---|
token | string | JWT token for frontend use |
expiresIn | number | Seconds until expiration |
The token is a JWT containing:
json{ "customerId": "user_abc123", "datasetId": "customer-support", "iat": 1702384000, "exp": 1702387600 }
bashcurl -X POST https://api.easyrag.com/v1/tokens/create \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "datasetId": "user-123-docs", "ttlSeconds": 3600 }'
javascriptconst response = await fetch('https://api.easyrag.com/v1/tokens/create', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId: 'user-123-docs', ttlSeconds: 3600 }) }); const { token, expiresIn } = await response.json();
pythonimport requests response = requests.post( 'https://api.easyrag.com/v1/tokens/create', headers={ 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' }, json={ 'datasetId': 'user-123-docs', 'ttlSeconds': 3600 } ) data = response.json() token = data['token'] expires_in = data['expiresIn']
Missing datasetId
json{ "error": "datasetId is required" }
Invalid ttlSeconds
json{ "error": "ttlSeconds must be between 1 and 86400" }
Missing API key
json{ "error": "Missing API key" }
Invalid API key
json{ "error": "Invalid API key" }
Frontend token used (not allowed)
json{ "error": "Missing API key" }
json{ "error": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please try again later.", "retryAfter": 60 }
X-RateLimit-* headersThis endpoint should only be called from your backend:
javascript// ✅ GOOD: Backend generates token app.post('/api/token', authenticateUser, async (req, res) => { const token = await createEasyRAGToken( `user-${req.user.id}`, 3600 ); res.json({ token }); }); // ❌ BAD: Frontend calls directly (exposes API key) const token = await fetch('https://api.easyrag.com/v1/tokens/create', { headers: { 'Authorization': `Bearer ${apiKey}` } // API key in frontend! });
Always verify the user should access the dataset:
javascriptapp.post('/api/token', authenticateUser, async (req, res) => { const { datasetId } = req.body; // Verify user owns this dataset const hasAccess = await checkUserAccess(req.user.id, datasetId); if (!hasAccess) { return res.status(403).json({ error: 'Access denied' }); } const token = await createEasyRAGToken(datasetId, 3600); res.json({ token }); });
| Use Case | Recommended TTL |
|---|---|
| Single file upload | 300s (5 min) |
| Chat session | 3600s (1 hour) |
| Mobile app session | 14400s (4 hours) |
| Admin panel | 86400s (24 hours) |
Once created, use the token like an API key:
javascript// Upload file const formData = new FormData(); formData.append('file', file); await fetch('https://api.easyrag.com/v1/files/upload', { method: 'POST', headers: { 'Authorization': `Bearer ${frontendToken}` // Use token }, body: formData }); // Search await fetch('https://api.easyrag.com/v1/search', { method: 'POST', headers: { 'Authorization': `Bearer ${frontendToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ question: 'What is the refund policy?' // datasetId is optional - embedded in token }) });
Frontend tokens are scoped to a single dataset:
javascript// Token for "project-a" const token = await createToken('project-a', 3600); // ✅ Works: Same dataset await upload(token, 'project-a', file); await search(token, 'project-a', query); // ❌ Fails: Different dataset await upload(token, 'project-b', file); // Response: 403 "datasetId mismatch between token and request"
javascript// ✅ Good: New token per session app.get('/chat', async (req, res) => { const token = await createToken(req.user.datasetId, 3600); res.render('chat', { token }); }); // ❌ Bad: Reuse long-lived token const globalToken = await createToken('dataset', 86400); // Don't share across users
javascript// Store expiry time const { token, expiresIn } = await createToken(datasetId, 3600); const expiresAt = Date.now() + (expiresIn * 1000); // Refresh before expiry setTimeout(async () => { const newToken = await createToken(datasetId, 3600); updateToken(newToken); }, (expiresIn - 60) * 1000); // Refresh 1 min before expiry
javascript// Quick upload const uploadToken = await createToken(datasetId, 300); // 5 min // Chat session const chatToken = await createToken(datasetId, 3600); // 1 hour // Long-running process const processToken = await createToken(datasetId, 86400); // 24 hours
javascriptimport { createEasyRAGToken } from './easyrag-client'; app.post('/api/easyrag-token', authenticateUser, async (req, res) => { try { const { datasetId } = req.body; // Validate datasetId if (!datasetId) { return res.status(400).json({ error: 'datasetId required' }); } // Check user access const userDataset = `user-${req.user.id}`; if (datasetId !== userDataset) { return res.status(403).json({ error: 'Access denied' }); } // Create token const response = await fetch('https://api.easyrag.com/v1/tokens/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.EASYRAG_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ datasetId, ttlSeconds: 3600 }) }); if (!response.ok) { throw new Error('Token creation failed'); } const { token, expiresIn } = await response.json(); res.json({ token, expiresIn }); } catch (error) { console.error('Token creation error:', error); res.status(500).json({ error: 'Failed to create token' }); } });
javascriptimport { useState, useEffect } from 'react'; function useEasyRAGToken(datasetId) { const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { let refreshTimeout; async function fetchToken() { try { setLoading(true); const response = await fetch('/api/easyrag-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ datasetId }) }); if (!response.ok) { throw new Error('Failed to get token'); } const { token, expiresIn } = await response.json(); setToken(token); setError(null); // Refresh 1 minute before expiry refreshTimeout = setTimeout(fetchToken, (expiresIn - 60) * 1000); } catch (err) { setError(err.message); } finally { setLoading(false); } } fetchToken(); return () => { if (refreshTimeout) clearTimeout(refreshTimeout); }; }, [datasetId]); return { token, loading, error }; } // Usage function MyComponent({ datasetId }) { const { token, loading, error } = useEasyRAGToken(datasetId); if (loading) return <div>Loading...</div>; if (error) return <div>Error: {error}</div>; return <FileUpload token={token} datasetId={datasetId} />; }
Decode the JWT to inspect claims:
javascript// Decode JWT (note: signature verification should happen server-side) const [header, payload, signature] = token.split('.'); const decoded = JSON.parse(atob(payload)); console.log('Customer:', decoded.customerId); console.log('Dataset:', decoded.datasetId); console.log('Expires:', new Date(decoded.exp * 1000));
javascript// Test token with a simple request const testToken = async (token) => { try { const response = await fetch( 'https://api.easyrag.com/v1/files?datasetId=test', { headers: { 'Authorization': `Bearer ${token}` } } ); if (response.ok) { console.log('✅ Token is valid'); } else { console.log('❌ Token is invalid:', response.status); } } catch (error) { console.log('❌ Token test failed:', error); } };
/v1/tokens/createAPI keys are used directly without a creation endpoint.
httpAuthorization: Bearer YOUR_API_KEY
or
httpx-easyrag-key: YOUR_API_KEY
Same limits apply to both API keys and frontend tokens (shared per customer).