Complete API documentation for CryptoScope.
| Property | Value |
|---|---|
| Base URL | http://localhost:3000 |
| API Version | /api/v1 |
| Format | JSON |
| Documentation | /api-docs/swagger-ui |
| OpenAPI Spec | /api-docs/openapi.json |
When the server is running, access:
- Swagger UI: http://localhost:3000/api-docs/swagger-ui
- OpenAPI JSON: http://localhost:3000/api-docs/openapi.json
| Property | Value |
|---|---|
| Type | JWT (JSON Web Token) |
| Password Hashing | Argon2id |
| Token Location | Authorization header |
| Format | Bearer <token> |
Endpoint: POST /api/v1/auth/login
Request:
{
"username": "admin",
"password": "your-password"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2024-01-01T12:00:00Z"
}Include the token in all protected endpoint requests:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
http://localhost:3000/api/v1/refreshBefore first login, generate a password hash:
# Using the binary
cargo run --bin generate-hash
# Or in Docker
docker compose run backend cargo run --bin generate-hashNo authentication required.
GET /health
Check if the service is running.
Response:
{
"status": "healthy",
"timestamp": "2024-01-01T12:00:00Z"
}GET /api/v1/exchanges
Get list of available exchanges.
Response:
[
{
"id": "bybit",
"name": "Bybit V5",
"supported": true
}
]GET /api/v1/symbols
Fetch symbols for an exchange.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
exchange |
string | Yes | Exchange ID (e.g., bybit) |
category |
string | No | linear, inverse, spot |
search |
string | No | Filter by symbol name |
Example:
curl "http://localhost:3000/api/v1/symbols?exchange=bybit&category=linear"Response:
[
{
"symbol": "BTCUSDT",
"base": "BTC",
"quote": "USDT",
"contract_type": "linear_perpetual",
"status": "trading"
}
]GET /api/v1/stats
Get cache statistics.
Response:
{
"total_symbols": 1250,
"last_updated": "2024-01-01T12:00:00Z",
"cache_hit_rate": 0.95
}GET /api/v1/screener
Run market screener with filters.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
exchange |
string | bybit |
Exchange ID |
min_change |
number | 0 |
Minimum price change % |
min_volume |
number | 0 |
Minimum 24h volume |
top |
integer | 0 |
Limit to top N results |
search |
string | - | Filter by symbol name |
contract_type |
string | - | linear, inverse, etc. |
Example:
curl "http://localhost:3000/api/v1/screener?exchange=bybit&min_change=5&top=10"Response:
[
{
"symbol": "BTCUSDT",
"price_change_24h": 5.23,
"volume_24h": 1500000000,
"current_price": 45000.00
}
]POST /api/v1/auth/login
Authenticate and get JWT token.
Request Body:
{
"username": "admin",
"password": "your-password"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2024-01-01T12:00:00Z"
}Requires JWT authentication.
POST /api/v1/refresh
Manually refresh the price cache (admin only).
Headers:
Authorization: Bearer <token>
Response:
{
"status": "refreshed",
"symbols_updated": 1250,
"timestamp": "2024-01-01T12:00:00Z"
}Example:
curl -X POST \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
http://localhost:3000/api/v1/refresh| Endpoint Type | Rate Limit | Burst Size |
|---|---|---|
| General API | 50 req/s | 100 |
| Authentication | 10 req/min | 5 |
| Cache Refresh | 5 req/min | 2 |
Rate limits are configurable via environment variables:
RATE_LIMIT_PER_SECOND=50
RATE_LIMIT_BURST_SIZE=100Responses include rate limit information:
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704110400
Response (429):
{
"error": "Rate limit exceeded",
"retry_after": 60
}{
"error": "Error message",
"code": "ERROR_CODE",
"details": {}
}| Code | HTTP Status | Description |
|---|---|---|
UNAUTHORIZED |
401 | Missing or invalid JWT token |
FORBIDDEN |
403 | Insufficient permissions |
NOT_FOUND |
404 | Resource not found |
BAD_REQUEST |
400 | Invalid request parameters |
RATE_LIMITED |
429 | Too many requests |
INTERNAL_ERROR |
500 | Server error |
Request: Invalid token
curl -H "Authorization: Bearer invalid-token" \
http://localhost:3000/api/v1/refreshResponse (401):
{
"error": "Invalid token",
"code": "UNAUTHORIZED"
}# 1. Login and get token
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}' \
| jq -r '.token')
# 2. Get symbols
curl "http://localhost:3000/api/v1/symbols?exchange=bybit"
# 3. Run screener
curl "http://localhost:3000/api/v1/screener?min_change=5&top=10"
# 4. Refresh cache (protected)
curl -X POST http://localhost:3000/api/v1/refresh \
-H "Authorization: Bearer $TOKEN"
# 5. Get stats
curl http://localhost:3000/api/v1/statsconst API_BASE = 'http://localhost:3000/api/v1';
// Login
async function login(username, password) {
const res = await fetch(`${API_BASE}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const { token } = await res.json();
return token;
}
// Fetch symbols
async function getSymbols(exchange, token) {
const res = await fetch(`${API_BASE}/symbols?exchange=${exchange}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
return res.json();
}import requests
API_BASE = 'http://localhost:3000/api/v1'
# Login
def login(username, password):
res = requests.post(f'{API_BASE}/auth/login',
json={'username': username, 'password': password})
return res.json()['token']
# Fetch symbols
def get_symbols(exchange, token):
headers = {'Authorization': f'Bearer {token}'}
res = requests.get(f'{API_BASE}/symbols?exchange={exchange}',
headers=headers)
return res.json()Error: 401 Unauthorized with message "Token has expired"
Solution:
- Tokens expire after 24 hours by default
- Re-authenticate:
POST /api/v1/auth/loginwith your credentials - Store the new token and update your Authorization header
Error: 429 Too Many Requests
Solution:
- Check the
Retry-Afterheader for how long to wait - Default limits:
- Public endpoints: 50 req/s (burst: 100)
- Authenticated endpoints: 10 req/s (burst: 20)
- Cache refresh: 2 req/s (burst: 5)
- Implement exponential backoff in your client
- For higher limits: adjust
RATE_LIMIT_PER_SECONDin config
Error: Blank page at /api-docs/swagger-ui
Solution:
- Ensure backend is running on port 3000
- Check browser console for CORS errors
- Verify
CORS_ORIGINSincludes your browser's origin - Try the OpenAPI JSON directly:
/api-docs/openapi.json
Error: 404 Not Found on valid endpoints
Solution:
- Ensure you're using the correct base path:
/api/v1/... - Check that the endpoint exists (see Public Endpoints)
- Verify backend logs for routing errors
- Configuration Guide - Environment variables
- Deployment Guide - Docker setup
- Development Guide - Local development