API Reference

Authentication

API keys and token endpoints

Technical reference for authentication endpoints.

POST /v1/tokens/create

Create a frontend token for browser/mobile applications.

Authentication

Required: API key only (frontend tokens cannot create tokens)

Headers

http
Authorization: Bearer YOUR_API_KEY Content-Type: application/json

Request Body

json
{ "datasetId": "string", "ttlSeconds": number }

Parameters

ParameterTypeRequiredDefaultConstraintsDescription
datasetIdstringYes-1-100 charsDataset the token can access
ttlSecondsnumberNo36001-86400Token lifetime in seconds (max 24 hours)

Response (200)

json
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": 3600 }

Response Fields

FieldTypeDescription
tokenstringJWT token for frontend use
expiresInnumberSeconds until expiration

Token Structure (JWT)

The token is a JWT containing:

json
{ "customerId": "user_abc123", "datasetId": "customer-support", "iat": 1702384000, "exp": 1702387600 }

Examples

cURL

bash
curl -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 }'

JavaScript

javascript
const 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();

Python

python
import 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']

Error Responses

400 Bad Request

Missing datasetId

json
{ "error": "datasetId is required" }

Invalid ttlSeconds

json
{ "error": "ttlSeconds must be between 1 and 86400" }

401 Unauthorized

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" }

429 Too Many Requests

json
{ "error": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please try again later.", "retryAfter": 60 }

Rate Limits

  • Limit: 100 requests/minute per customer
  • Scope: Applies to all token creation requests
  • Headers: Response includes X-RateLimit-* headers

Security Considerations

Backend Only

This 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! });

Validate User Access

Always verify the user should access the dataset:

javascript
app.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 }); });

Token Lifetime Recommendations

Use CaseRecommended TTL
Single file upload300s (5 min)
Chat session3600s (1 hour)
Mobile app session14400s (4 hours)
Admin panel86400s (24 hours)

Token Usage

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 }) });

Token Scoping

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"

Best Practices

1. Generate Per-Session

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

2. Refresh Before Expiry

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

3. Match TTL to Use Case

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

Implementation Examples

Express.js Endpoint

javascript
import { 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' }); } });

React Hook

javascript
import { 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} />; }

Debugging

Check Token Validity

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));

Verify Token Works

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); } };

Notes

  • Tokens cannot create other tokens (only API keys can)
  • Token expiration is enforced server-side
  • Expired tokens return 401 Unauthorized
  • Tokens are stateless JWTs (not stored in database)
  • No way to revoke a token before expiry
  • Rate limits apply per customer, not per token

Related Endpoints

  • All endpoints accept frontend tokens except /v1/tokens/create
  • See individual endpoint docs for token usage details

API Key Usage

API keys are used directly without a creation endpoint.

Headers

http
Authorization: Bearer YOUR_API_KEY

or

http
x-easyrag-key: YOUR_API_KEY

Getting API Keys

  1. Sign up at easyrag.com
  2. Navigate to Settings → API Keys
  3. Click Generate API Key
  4. Copy and store securely (shown only once)

Security

  • Store in environment variables
  • Never commit to version control
  • Use different keys for dev/staging/prod
  • Rotate periodically
  • Keep server-side only

Rate Limits

Same limits apply to both API keys and frontend tokens (shared per customer).